• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libunwind - a platform-independent unwind library
2    Copyright (C) 2003-2004 Hewlett-Packard Co
3         Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4 
5 This file is part of libunwind.
6 
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14 
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25 
26 #include <fcntl.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include <sys/mman.h>
31 
32 #include "libunwind_i.h"
33 #include "dwarf-eh.h"
34 #include "dwarf_i.h"
35 
36 #define to_unw_word(p) ((unw_word_t) (uintptr_t) (p))
37 #ifndef PAGE_SIZE
38 #define PAGE_SIZE 4096
39 #endif
40 /* Add For Cache MAP And ELF */
41 int
dwarf_find_unwind_table(struct elf_dyn_info * edi,struct elf_image * ei,unw_addr_space_t as,char * path,unw_word_t segbase,unw_word_t mapoff,unw_word_t ip)42 dwarf_find_unwind_table (struct elf_dyn_info *edi, struct elf_image *ei,
43 			 unw_addr_space_t as, char *path,
44 			 unw_word_t segbase, unw_word_t mapoff, unw_word_t ip)
45 /* Add For Cache MAP And ELF */
46 {
47   Elf_W(Phdr) *phdr, *ptxt = NULL, *peh_hdr = NULL, *pdyn = NULL;
48   unw_word_t addr, eh_frame_start, fde_count, load_base;
49   unw_word_t max_load_addr = 0;
50   unw_word_t start_ip = to_unw_word (-1);
51   unw_word_t end_ip = 0;
52   struct dwarf_eh_frame_hdr *hdr;
53   unw_proc_info_t pi;
54   unw_accessors_t *a;
55   Elf_W(Ehdr) *ehdr;
56   int first_load_section = 0;
57   int first_load_offset = 0;
58 #if UNW_TARGET_ARM
59   const Elf_W(Phdr) *parm_exidx = NULL;
60 #endif
61   int i, ret, found = 0;
62 
63   /* XXX: Much of this code is Linux/LSB-specific.  */
64 
65   /* Add For Cache MAP And ELF */
66   if (!elf_w(valid_object) (ei))
67   /* Add For Cache MAP And ELF */
68     return -UNW_ENOINFO;
69 
70   if (ei->has_dyn_info == 1 &&
71       ei->elf_dyn_info.start_ip <= ip &&
72       ei->elf_dyn_info.end_ip >= ip) {
73     *edi = ei->elf_dyn_info;
74     return 1; // found
75   }
76   /* Add For Cache MAP And ELF */
77   ehdr = ei->image;
78   phdr = (Elf_W(Phdr) *) ((char *) ei->image + ehdr->e_phoff);
79   /* Add For Cache MAP And ELF */
80 
81 
82   unsigned long pagesize_alignment_mask = ~(((unsigned long)getpagesize()) - 1UL);
83   for (i = 0; i < ehdr->e_phnum; ++i)
84     {
85       switch (phdr[i].p_type)
86         {
87         case PT_LOAD:
88           if ((phdr[i].p_flags & PF_X) == 0) {
89             continue;
90           }
91 
92           if (first_load_section == 0) {
93             ei->load_bias = phdr[i].p_vaddr - phdr[i].p_offset;
94             first_load_section = 1;
95           }
96 
97           if (phdr[i].p_vaddr < start_ip)
98             start_ip = phdr[i].p_vaddr;
99 
100           if (phdr[i].p_vaddr + phdr[i].p_memsz > end_ip)
101             end_ip = phdr[i].p_vaddr + phdr[i].p_memsz;
102 
103           if ((phdr[i].p_offset & (-PAGE_SIZE)) == mapoff)
104             ptxt = phdr + i;
105 
106           if (first_load_offset == 0) {
107             if ((phdr[i].p_offset & pagesize_alignment_mask) == mapoff) {
108               ei->load_offset = phdr[i].p_vaddr - (phdr[i].p_offset & (~pagesize_alignment_mask));
109               first_load_offset = 1;
110             } else {
111               ei->load_offset = 0;
112             }
113           }
114 
115           /* Add For Cache MAP And ELF */
116           if ((uintptr_t) ei->image + phdr->p_filesz > max_load_addr)
117             max_load_addr = (uintptr_t) ei->image + phdr->p_filesz;
118           break;
119           /* Add For Cache MAP And ELF */
120 
121         case PT_GNU_EH_FRAME:
122 #if defined __sun
123         case PT_SUNW_UNWIND:
124 #endif
125           peh_hdr = phdr + i;
126           break;
127 
128         case PT_DYNAMIC:
129           pdyn = phdr + i;
130           break;
131 
132 #if UNW_TARGET_ARM
133         case PT_ARM_EXIDX:
134           parm_exidx = phdr + i;
135           break;
136 #endif
137 
138         default:
139           break;
140         }
141     }
142 
143   if (!ptxt)
144     return 0;
145 
146   load_base = segbase - (ptxt->p_vaddr & (-PAGE_SIZE));
147   start_ip += load_base;
148   end_ip += load_base;
149 
150   if (peh_hdr)
151     {
152       if (pdyn)
153         {
154           /* For dynamicly linked executables and shared libraries,
155              DT_PLTGOT is the value that data-relative addresses are
156              relative to for that object.  We call this the "gp".  */
157 		/* Add For Cache MAP And ELF */
158                 Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(pdyn->p_offset
159 						 + (char *) ei->image);
160 		/* Add For Cache MAP And ELF */
161           for (; dyn->d_tag != DT_NULL; ++dyn)
162             if (dyn->d_tag == DT_PLTGOT)
163               {
164                 /* Assume that _DYNAMIC is writable and GLIBC has
165                    relocated it (true for x86 at least).  */
166                 edi->di_cache.gp = dyn->d_un.d_ptr;
167                 break;
168               }
169         }
170       else
171         /* Otherwise this is a static executable with no _DYNAMIC.  Assume
172            that data-relative addresses are relative to 0, i.e.,
173            absolute.  */
174         edi->di_cache.gp = 0;
175 
176       /* Add For Cache MAP And ELF */
177       hdr = (struct dwarf_eh_frame_hdr *) (peh_hdr->p_offset
178 					   + (char *) ei->image);
179       /* Add For Cache MAP And ELF */
180       if (hdr->version != DW_EH_VERSION)
181         {
182           Debug (1, "table `%s' has unexpected version %d\n",
183                  path, hdr->version);
184           return -UNW_ENOINFO;
185         }
186 
187       a = unw_get_accessors_int (unw_local_addr_space);
188       addr = to_unw_word (&hdr->eh_frame);
189 
190       /* Fill in a dummy proc_info structure.  We just need to fill in
191          enough to ensure that dwarf_read_encoded_pointer() can do it's
192          job.  Since we don't have a procedure-context at this point, all
193          we have to do is fill in the global-pointer.  */
194       memset (&pi, 0, sizeof (pi));
195       pi.gp = edi->di_cache.gp;
196 
197       /* (Optionally) read eh_frame_ptr: */
198       if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
199                                              &addr, hdr->eh_frame_ptr_enc, &pi,
200                                              &eh_frame_start, NULL)) < 0)
201         return -UNW_ENOINFO;
202 
203       /* (Optionally) read fde_count: */
204       if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
205                                              &addr, hdr->fde_count_enc, &pi,
206                                              &fde_count, NULL)) < 0)
207         return -UNW_ENOINFO;
208 
209       if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
210         {
211     #if 1
212           abort ();
213     #else
214           unw_word_t eh_frame_end;
215 
216           /* If there is no search table or it has an unsupported
217              encoding, fall back on linear search.  */
218           if (hdr->table_enc == DW_EH_PE_omit)
219             Debug (4, "EH lacks search table; doing linear search\n");
220           else
221             Debug (4, "EH table has encoding 0x%x; doing linear search\n",
222                    hdr->table_enc);
223 
224           eh_frame_end = max_load_addr; /* XXX can we do better? */
225 
226           if (hdr->fde_count_enc == DW_EH_PE_omit)
227             fde_count = ~0UL;
228           if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit)
229             abort ();
230 
231           return linear_search (unw_local_addr_space, ip,
232                                 eh_frame_start, eh_frame_end, fde_count,
233                                 pi, need_unwind_info, NULL);
234     #endif
235         }
236 
237       edi->di_cache.start_ip = start_ip;
238       edi->di_cache.end_ip = end_ip;
239       edi->di_cache.load_offset = 0;
240       edi->di_cache.format = UNW_INFO_FORMAT_REMOTE_TABLE;
241       edi->di_cache.u.rti.name_ptr = 0;
242       /* two 32-bit values (ip_offset/fde_offset) per table-entry: */
243       edi->di_cache.u.rti.table_len = (fde_count * 8) / sizeof (unw_word_t);
244       edi->di_cache.u.rti.table_data = ((load_base + peh_hdr->p_vaddr)
245 				       + (addr - (unw_word_t) ei->image
246                                           - peh_hdr->p_offset));
247 
248       /* For the binary-search table in the eh_frame_hdr, data-relative
249          means relative to the start of that section... */
250       /* Add For Cache MAP And ELF */
251       edi->di_cache.u.rti.segbase = ((load_base + peh_hdr->p_vaddr)
252 				    + ((unw_word_t) hdr - (unw_word_t) ei->image
253 				       - peh_hdr->p_offset));
254       /* Add For Cache MAP And ELF */
255       found = 1;
256     }
257 
258 #if UNW_TARGET_ARM
259   if (parm_exidx)
260     {
261       edi->di_arm.format = UNW_INFO_FORMAT_ARM_EXIDX;
262       edi->di_arm.start_ip = start_ip;
263       edi->di_arm.end_ip = end_ip;
264       edi->di_arm.u.rti.name_ptr = to_unw_word (path);
265       edi->di_arm.u.rti.table_data = load_base + parm_exidx->p_vaddr;
266       edi->di_arm.u.rti.table_len = parm_exidx->p_memsz;
267       found = 1;
268     }
269 #endif
270 
271 #ifdef CONFIG_DEBUG_FRAME
272   /* Try .debug_frame. */
273   found = dwarf_find_debug_frame (found, &edi->di_debug, ip, load_base, path,
274                                   start_ip, end_ip);
275 #endif
276   if (found == 1) {
277     edi->start_ip = start_ip;
278     edi->end_ip = end_ip;
279     ei->elf_dyn_info = *edi;
280     ei->has_dyn_info = 1;
281   }
282   return found;
283 }
284