• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libunwind - a platform-independent unwind library
2    Copyright (C) 2003-2005 Hewlett-Packard Co
3    Copyright (C) 2007 David Mosberger-Tang
4         Contributed by David Mosberger-Tang <dmosberger@gmail.com>
5 
6 This file is part of libunwind.
7 
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
15 
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
26 
27 #include "libunwind_i.h"
28 
29 #include <stdio.h>
30 #include <sys/param.h>
31 #include <limits.h>
32 
33 #ifdef HAVE_LZMA
34 #include <lzma.h>
35 #endif /* HAVE_LZMA */
36 
Elf_W(Shdr)37 static Elf_W (Shdr)*
38 elf_w (section_table) (struct elf_image *ei)
39 {
40   Elf_W (Ehdr) *ehdr = ei->image;
41   Elf_W (Off) soff;
42 
43   soff = ehdr->e_shoff;
44   if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->size)
45     {
46       Debug (1, "section table outside of image? (%lu > %lu)\n",
47              (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize),
48              (unsigned long) ei->size);
49       return NULL;
50     }
51 
52   return (Elf_W (Shdr) *) ((char *) ei->image + soff);
53 }
54 
55 static char*
elf_w(string_table)56 elf_w (string_table) (struct elf_image *ei, int section)
57 {
58   Elf_W (Ehdr) *ehdr = ei->image;
59   Elf_W (Off) soff, str_soff;
60   Elf_W (Shdr) *str_shdr;
61 
62   /* this offset is assumed to be OK */
63   soff = ehdr->e_shoff;
64 
65   str_soff = soff + (section * ehdr->e_shentsize);
66   if (str_soff + ehdr->e_shentsize > ei->size)
67     {
68       Debug (1, "string shdr table outside of image? (%lu > %lu)\n",
69              (unsigned long) (str_soff + ehdr->e_shentsize),
70              (unsigned long) ei->size);
71       return NULL;
72     }
73   str_shdr = (Elf_W (Shdr) *) ((char *) ei->image + str_soff);
74 
75   if (str_shdr->sh_offset + str_shdr->sh_size > ei->size)
76     {
77       Debug (1, "string table outside of image? (%lu > %lu)\n",
78              (unsigned long) (str_shdr->sh_offset + str_shdr->sh_size),
79              (unsigned long) ei->size);
80       return NULL;
81     }
82 
83   Debug (16, "strtab=0x%lx\n", (long) str_shdr->sh_offset);
84   return ei->image + str_shdr->sh_offset;
85 }
86 
87 static int
elf_w(lookup_symbol)88 elf_w (lookup_symbol) (unw_addr_space_t as,
89                        unw_word_t ip, struct elf_image *ei,
90                        Elf_W (Addr) load_offset,
91                        char *buf, size_t buf_len, Elf_W (Addr) *min_dist)
92 {
93   size_t syment_size;
94   Elf_W (Ehdr) *ehdr = ei->image;
95   Elf_W (Sym) *sym, *symtab, *symtab_end;
96   Elf_W (Shdr) *shdr;
97   Elf_W (Addr) val;
98   int i, ret = -UNW_ENOINFO;
99   char *strtab;
100 
101   if (!elf_w (valid_object) (ei))
102     return -UNW_ENOINFO;
103 
104   shdr = elf_w (section_table) (ei);
105   if (!shdr)
106     return -UNW_ENOINFO;
107 
108   for (i = 0; i < ehdr->e_shnum; ++i)
109     {
110       switch (shdr->sh_type)
111         {
112         case SHT_SYMTAB:
113         case SHT_DYNSYM:
114           symtab = (Elf_W (Sym) *) ((char *) ei->image + shdr->sh_offset);
115           symtab_end = (Elf_W (Sym) *) ((char *) symtab + shdr->sh_size);
116           syment_size = shdr->sh_entsize;
117 
118           strtab = elf_w (string_table) (ei, shdr->sh_link);
119           if (!strtab)
120             break;
121 
122           Debug (16, "symtab=0x%lx[%d]\n",
123                  (long) shdr->sh_offset, shdr->sh_type);
124 
125           for (sym = symtab;
126                sym < symtab_end;
127                sym = (Elf_W (Sym) *) ((char *) sym + syment_size))
128             {
129               if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC
130                   && sym->st_shndx != SHN_UNDEF)
131                 {
132                   val = sym->st_value;
133                   if (sym->st_shndx != SHN_ABS)
134                     val += load_offset;
135                   if (tdep_get_func_addr (as, val, &val) < 0)
136                     continue;
137                   Debug (16, "0x%016lx info=0x%02x %s\n",
138                          (long) val, sym->st_info, strtab + sym->st_name);
139 
140                   if ((Elf_W (Addr)) (ip - val) < *min_dist)
141                     {
142                       *min_dist = (Elf_W (Addr)) (ip - val);
143                       strncpy (buf, strtab + sym->st_name, buf_len);
144                       buf[buf_len - 1] = '\0';
145                       ret = (strlen (strtab + sym->st_name) >= buf_len
146                              ? -UNW_ENOMEM : 0);
147                     }
148                 }
149             }
150           break;
151 
152         default:
153           break;
154         }
155       shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
156     }
157   return ret;
158 }
159 
160 static int
elf_w(find_symbol_info_in_image)161 elf_w (find_symbol_info_in_image) (struct elf_image *ei,
162                                    unw_word_t load_offset,
163                                    uint64_t pc,
164                                    int buf_sz,
165                                    char *buf,
166                                    uint64_t *sym_start,
167                                    uint64_t *sym_end)
168 {
169   size_t syment_size;
170   Elf_W (Ehdr) *ehdr = ei->image;
171   Elf_W (Sym) *sym, *symtab, *symtab_end;
172   Elf_W (Shdr) *shdr;
173   Elf_W (Addr) val;
174   int i, ret = -UNW_ENOINFO;
175   char *strtab;
176   uint64_t start = 0;
177   uint64_t end = 0;
178 
179   if (!elf_w (valid_object) (ei))
180     return -UNW_ENOINFO;
181 
182   shdr = elf_w (section_table) (ei);
183   if (!shdr)
184     return -UNW_ENOINFO;
185 
186   for (i = 0; i < ehdr->e_shnum; ++i)
187     {
188       switch (shdr->sh_type)
189         {
190         case SHT_SYMTAB:
191         case SHT_DYNSYM:
192           symtab = (Elf_W (Sym) *) ((char *) ei->image + shdr->sh_offset);
193           symtab_end = (Elf_W (Sym) *) ((char *) symtab + shdr->sh_size);
194           syment_size = shdr->sh_entsize;
195           strtab = elf_w (string_table) (ei, shdr->sh_link);
196           if (!strtab) {
197             Dprintf( "no strtab?\n");
198             break;
199           }
200 
201           if (!ei->strtab) {
202             ei->strtab = strtab;
203           }
204 
205           for (sym = symtab;
206                sym < symtab_end;
207                sym = (Elf_W (Sym) *) ((char *) sym + syment_size))
208             {
209               if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC
210                   && sym->st_shndx != SHN_UNDEF)
211                 {
212                   val = sym->st_value;
213                   if (sym->st_shndx != SHN_ABS)
214                     val += load_offset;
215                   start = (uint64_t)val;
216                   end = start + (uint64_t)sym->st_size;
217                   if (pc >= start && pc < end) {
218                     strncpy (buf, strtab + sym->st_name, buf_sz);
219                     buf[buf_sz - 1] = '\0';
220                     *sym_start = start;
221                     *sym_end = end;
222                     return 0;
223                   }
224                 }
225             }
226           break;
227 
228         default:
229           break;
230         }
231       shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
232     }
233   return ret;
234 }
235 
236 static Elf_W (Addr)
elf_w(get_load_offset)237 elf_w (get_load_offset) (struct elf_image *ei, unsigned long segbase,
238                          unsigned long mapoff)
239 {
240   Elf_W (Addr) offset = 0;
241   Elf_W (Ehdr) *ehdr;
242   Elf_W (Phdr) *phdr;
243   int i;
244   // mapoff is obtained from mmap informations, so is always aligned on a page size.
245   // PT_LOAD program headers p_offset however is not guaranteed to be aligned on a
246   // page size, ld.lld generate libraries where this is not the case. So we must
247   // make sure we compare both values with the same alignment.
248   unsigned long pagesize_alignment_mask = ~(((unsigned long)getpagesize()) - 1UL);
249 
250   ehdr = ei->image;
251   phdr = (Elf_W (Phdr) *) ((char *) ei->image + ehdr->e_phoff);
252 
253   for (i = 0; i < ehdr->e_phnum; ++i)
254     if (phdr[i].p_type == PT_LOAD && (phdr[i].p_offset & pagesize_alignment_mask) == mapoff)
255       {
256         offset = segbase - phdr[i].p_vaddr + (phdr[i].p_offset & (~pagesize_alignment_mask));
257         break;
258       }
259 
260   return offset;
261 }
262 
263 #if HAVE_LZMA
264 static size_t
xz_uncompressed_size(uint8_t * compressed,size_t length)265 xz_uncompressed_size (uint8_t *compressed, size_t length)
266 {
267   uint64_t memlimit = UINT64_MAX;
268   size_t ret = 0, pos = 0;
269   lzma_stream_flags options;
270   lzma_index *index;
271 
272   if (length < LZMA_STREAM_HEADER_SIZE)
273     return 0;
274 
275   uint8_t *footer = compressed + length - LZMA_STREAM_HEADER_SIZE;
276   if (lzma_stream_footer_decode (&options, footer) != LZMA_OK)
277     return 0;
278 
279   if (length < LZMA_STREAM_HEADER_SIZE + options.backward_size)
280     return 0;
281 
282   uint8_t *indexdata = footer - options.backward_size;
283   if (lzma_index_buffer_decode (&index, &memlimit, NULL, indexdata,
284                                 &pos, options.backward_size) != LZMA_OK)
285     return 0;
286 
287   if (lzma_index_size (index) == options.backward_size)
288     {
289       ret = lzma_index_uncompressed_size (index);
290     }
291 
292   lzma_index_end (index, NULL);
293   return ret;
294 }
295 
296 static int
elf_w(extract_minidebuginfo)297 elf_w (extract_minidebuginfo) (struct elf_image *ei, struct elf_image *mdi)
298 {
299   Elf_W (Shdr) *shdr;
300   uint8_t *compressed = NULL;
301   uint64_t memlimit = UINT64_MAX; /* no memory limit */
302   size_t compressed_len, uncompressed_len;
303   mdi->has_try_load = 1;
304   shdr = elf_w (find_section) (ei, ".gnu_debugdata");
305   if (!shdr)
306     return 0;
307 
308   compressed = ((uint8_t *) ei->image) + shdr->sh_offset;
309   compressed_len = shdr->sh_size;
310 
311   uncompressed_len = xz_uncompressed_size (compressed, compressed_len);
312   if (uncompressed_len == 0)
313     {
314       Dprintf("invalid .gnu_debugdata contents\n");
315       return 0;
316     }
317 
318   mdi->size = uncompressed_len;
319   mdi->image = mmap (NULL, uncompressed_len, PROT_READ|PROT_WRITE,
320                      MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
321 
322   if (mdi->image == MAP_FAILED)
323     return 0;
324 
325   size_t in_pos = 0, out_pos = 0;
326   lzma_ret lret;
327   lret = lzma_stream_buffer_decode (&memlimit, 0, NULL,
328                                     compressed, &in_pos, compressed_len,
329                                     mdi->image, &out_pos, mdi->size);
330   if (lret != LZMA_OK)
331     {
332       Dprintf( "LZMA decompression failed: %d\n", lret);
333       munmap (mdi->image, mdi->size);
334       mdi->image = NULL;
335       return 0;
336     }
337 
338   return 1;
339 }
340 #else
341 static int
elf_w(extract_minidebuginfo)342 elf_w (extract_minidebuginfo) (struct elf_image *ei, struct elf_image *mdi)
343 {
344   return 0;
345 }
346 #endif /* !HAVE_LZMA */
347 
348 /* Find the ELF image that contains IP and return the "closest"
349    procedure name, if there is one.  With some caching, this could be
350    sped up greatly, but until an application materializes that's
351    sensitive to the performance of this routine, why bother...  */
352 
353 HIDDEN int
elf_w(get_proc_name_in_image)354 elf_w (get_proc_name_in_image) (unw_addr_space_t as, struct elf_image *ei,
355                        unsigned long segbase,
356                        unsigned long mapoff,
357                        unw_word_t ip,
358                        char *buf, size_t buf_len, unw_word_t *offp)
359 {
360   Elf_W (Addr) load_offset;
361   Elf_W (Addr) min_dist = ~(Elf_W (Addr))0;
362   int ret;
363 
364   load_offset = segbase - ei->load_offset;
365   ret = elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, &min_dist);
366 
367   /* If the ELF image has MiniDebugInfo embedded in it, look up the symbol in
368      there as well and replace the previously found if it is closer. */
369   struct elf_image mdi;
370   if (elf_w (extract_minidebuginfo) (ei, &mdi))
371     {
372       int ret_mdi = elf_w (lookup_symbol) (as, ip, &mdi, load_offset, buf,
373                                            buf_len, &min_dist);
374 
375       /* Closer symbol was found (possibly truncated). */
376       if (ret_mdi == 0 || ret_mdi == -UNW_ENOMEM)
377         {
378           ret = ret_mdi;
379         }
380 
381       munmap (mdi.image, mdi.size);
382     }
383 
384   if (min_dist >= ei->size)
385     return -UNW_ENOINFO;                /* not found */
386   if (offp)
387     *offp = min_dist;
388   return ret;
389 }
390 
391 /* Add For Cache MAP And ELF */
392 HIDDEN int
elf_w(get_proc_name)393 elf_w (get_proc_name) (unw_addr_space_t as, pid_t pid, unw_word_t ip,
394                        char *buf, size_t buf_len, unw_word_t *offp)
395 {
396   int ret;
397   struct map_info *map = tdep_get_elf_image (as, pid, ip);
398 
399   if (map == NULL)
400     return -UNW_ENOINFO;
401 
402   ret = elf_w (get_proc_name_in_image) (as, &map->ei, map->start, map->offset, ip, buf, buf_len, offp);
403 
404   return ret;
405 }
406 /* Add For Cache MAP And ELF */
Elf_W(Shdr)407 HIDDEN Elf_W (Shdr)*
408 elf_w (find_section) (struct elf_image *ei, const char* secname)
409 {
410   Elf_W (Ehdr) *ehdr = ei->image;
411   Elf_W (Shdr) *shdr;
412   char *strtab;
413   int i;
414 
415   if (!elf_w (valid_object) (ei))
416     return 0;
417 
418   shdr = elf_w (section_table) (ei);
419   if (!shdr)
420     return 0;
421 
422   strtab = elf_w (string_table) (ei, ehdr->e_shstrndx);
423   if (!strtab)
424     return 0;
425 
426   for (i = 0; i < ehdr->e_shnum; ++i)
427     {
428       if (strcmp (strtab + shdr->sh_name, secname) == 0)
429         {
430           if (shdr->sh_offset + shdr->sh_size > ei->size)
431             {
432               Debug (1, "section \"%s\" outside image? (0x%lu > 0x%lu)\n",
433                      secname,
434                      (unsigned long) shdr->sh_offset + shdr->sh_size,
435                      (unsigned long) ei->size);
436               return 0;
437             }
438 
439           Debug (16, "found section \"%s\" at 0x%lx\n",
440                  secname, (unsigned long) shdr->sh_offset);
441           return shdr;
442         }
443 
444       shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
445     }
446 
447   /* section not found */
448   return 0;
449 }
450 
451 /* Load a debug section, following .gnu_debuglink if appropriate
452  * Loads ei from file if not already mapped.
453  * If is_local, will also search sys directories /usr/local/dbg
454  *
455  * Returns 0 on success, failure otherwise.
456  * ei will be mapped to file or the located .gnu_debuglink from file
457  */
458 HIDDEN int
elf_w(load_debuglink)459 elf_w (load_debuglink) (const char* file, struct elf_image *ei, int is_local)
460 {
461   int ret;
462   Elf_W (Shdr) *shdr;
463   Elf_W (Ehdr) *prev_image;
464   off_t prev_size;
465 
466   if (!ei->image)
467     {
468       ret = elf_map_image(ei, file);
469       if (ret)
470         return ret;
471     }
472 
473   prev_image = ei->image;
474   prev_size = ei->size;
475 
476   /* Ignore separate debug files which contain a .gnu_debuglink section. */
477   if (is_local == -1) {
478     return 0;
479   }
480 
481   shdr = elf_w (find_section) (ei, ".gnu_debuglink");
482   if (shdr) {
483     if (shdr->sh_size >= PATH_MAX ||
484 	(shdr->sh_offset + shdr->sh_size > ei->size))
485       {
486 	return 0;
487       }
488 
489     {
490       char linkbuf[shdr->sh_size];
491       char *link = ((char *) ei->image) + shdr->sh_offset;
492       char *p;
493       static const char *debugdir = "/usr/lib/debug";
494       char basedir[strlen(file) + 1];
495       char newname[shdr->sh_size + strlen (debugdir) + strlen (file) + 9];
496 
497       memcpy(linkbuf, link, shdr->sh_size);
498 
499       if (memchr (linkbuf, 0, shdr->sh_size) == NULL)
500 	return 0;
501 
502       ei->image = NULL;
503 
504       Debug(1, "Found debuglink section, following %s\n", linkbuf);
505 
506       p = strrchr (file, '/');
507       if (p != NULL)
508 	{
509 	  memcpy (basedir, file, p - file);
510 	  basedir[p - file] = '\0';
511 	}
512       else
513 	basedir[0] = 0;
514 
515       strcpy (newname, basedir);
516       strcat (newname, "/");
517       strcat (newname, linkbuf);
518       ret = elf_w (load_debuglink) (newname, ei, -1);
519 
520       if (ret == -1)
521 	{
522 	  strcpy (newname, basedir);
523 	  strcat (newname, "/.debug/");
524 	  strcat (newname, linkbuf);
525 	  ret = elf_w (load_debuglink) (newname, ei, -1);
526 	}
527 
528       if (ret == -1 && is_local == 1)
529 	{
530 	  strcpy (newname, debugdir);
531 	  strcat (newname, basedir);
532 	  strcat (newname, "/");
533 	  strcat (newname, linkbuf);
534 	  ret = elf_w (load_debuglink) (newname, ei, -1);
535 	}
536 
537       if (ret == -1)
538         {
539           /* No debuglink file found even though .gnu_debuglink existed */
540           ei->image = prev_image;
541           ei->size = prev_size;
542 
543           return 0;
544         }
545       else
546         {
547           munmap (prev_image, prev_size);
548         }
549 
550       return ret;
551     }
552   }
553 
554   return 0;
555 }
556 
elf_w(get_symbol_info_in_image)557 int elf_w (get_symbol_info_in_image) (struct elf_image *ei,
558                                       unsigned long segbase,
559                                       unsigned long mapoff,
560                                       uint64_t pc,
561                                       int buf_sz,
562                                       char *buf,
563                                       uint64_t *sym_start,
564                                       uint64_t *sym_end)
565 {
566   Elf_W (Addr) load_offset = elf_w (get_load_offset) (ei, segbase, mapoff);
567   int ret = elf_w (find_symbol_info_in_image) (ei, load_offset, pc, buf_sz, buf, sym_start, sym_end);
568   if (ret == 0) {
569     return ret;
570   }
571 
572   if (ei->mdi == NULL) {
573     return ret;
574   }
575 
576   if (ei->mdi->image == NULL && ei->mdi->has_try_load) {
577     return ret;
578   }
579 
580   if (ei->mdi->image != NULL || elf_w (extract_minidebuginfo) (ei, ei->mdi)) {
581       ret = elf_w (find_symbol_info_in_image) (ei->mdi, load_offset, pc, buf_sz, buf, sym_start, sym_end);
582   }
583   return ret;
584 }
585 
calc_elf_file_size(void * elf,size_t map_sz)586 size_t calc_elf_file_size (void* elf, size_t map_sz)
587 {
588   if (map_sz < sizeof(Elf_W (Ehdr))) {
589     Dprintf("invalid elf size? sz:%d, request sz:%d\n", (int)map_sz, (int)sizeof(Elf_W (Ehdr)));
590     return 0;
591   }
592 
593   // validate the magic number and version of elf
594   if (!(memcmp (elf, ELFMAG, SELFMAG) == 0
595     && ((uint8_t *) elf)[EI_CLASS] == UNW_ELF_CLASS
596     && ((uint8_t *) elf)[EI_VERSION] != EV_NONE
597     && ((uint8_t *) elf)[EI_VERSION] <= EV_CURRENT)) {
598     Dprintf("invalid elf hdr?\n");
599     return 0;
600   }
601 
602   Elf_W (Ehdr) *ehdr = elf;
603   return (ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum));
604 }