resetting manifest requested domain to floor
[platform/upstream/sysprof.git] / elfparser.c
1 /* Sysprof -- Sampling, systemwide CPU profiler
2  * Copyright 2006, 2007, Soeren Sandmann
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 #include <stdlib.h>
19 #include <string.h>
20 #include <elf.h>
21 #include <sys/mman.h>
22 #include "elfparser.h"
23
24 typedef struct Section Section;
25
26 struct ElfSym
27 {
28     gulong table;
29     gulong offset;
30     gulong address;
31 };
32
33 struct Section
34 {
35     const gchar *       name;
36     gsize               offset;
37     gsize               size;
38     gboolean            allocated;
39     gulong              load_address;
40     guint               type;
41 };
42
43 struct ElfParser
44 {
45     gboolean            is_64;
46     const guchar *      data;
47     gsize               length;
48     
49     int                 n_sections;
50     Section **          sections;
51     
52     int                 n_symbols;
53     ElfSym *            symbols;
54     gsize               sym_strings;
55     
56     GMappedFile *       file;
57
58     char *              filename;
59
60     gboolean            checked_build_id;
61     char *              build_id;
62     
63     const Section *     text_section;
64 };
65
66 /* FIXME: All of these should in principle do endian swapping,
67  * but sysprof never has to deal with binaries of a different
68  * endianness than sysprof itself
69  */
70 #define GET_FIELD(parser, offset, struct_name, idx, field_name)         \
71     (((parser))->is_64?                                                 \
72      ((Elf64_ ## struct_name *)(((parser)->data + offset)) + (idx))->field_name : \
73      ((Elf32_ ## struct_name *)(((parser)->data + offset)) + (idx))->field_name)
74
75 #define GET_UINT32(parser, offset)                                      \
76     *((uint32_t *)(parser->data + offset))                              \
77
78 #define GET_SIZE(parser, struct_name)                                   \
79     (((parser)->is_64?                                                  \
80       sizeof (Elf64_ ## struct_name) :                                  \
81       sizeof (Elf32_ ## struct_name)))
82
83 #define MAKE_ELF_UINT_ACCESSOR(field_name)                              \
84     static uint64_t field_name  (ElfParser *parser)                     \
85     {                                                                   \
86         return GET_FIELD (parser, 0, Ehdr, 0, field_name);              \
87     }
88
89 MAKE_ELF_UINT_ACCESSOR (e_shoff)
90 MAKE_ELF_UINT_ACCESSOR (e_shnum)
91 MAKE_ELF_UINT_ACCESSOR (e_shstrndx)
92
93 #define MAKE_SECTION_HEADER_ACCESSOR(field_name)                        \
94     static uint64_t field_name (ElfParser *parser, int nth_section)     \
95     {                                                                   \
96         gsize offset = e_shoff (parser);                                \
97                                                                         \
98         return GET_FIELD (parser, offset, Shdr, nth_section, field_name); \
99     }
100
101 MAKE_SECTION_HEADER_ACCESSOR (sh_name);
102 MAKE_SECTION_HEADER_ACCESSOR (sh_type);
103 MAKE_SECTION_HEADER_ACCESSOR (sh_flags);
104 MAKE_SECTION_HEADER_ACCESSOR (sh_addr);
105 MAKE_SECTION_HEADER_ACCESSOR (sh_offset);
106 MAKE_SECTION_HEADER_ACCESSOR (sh_size);
107
108 #define MAKE_SYMBOL_ACCESSOR(field_name)                                \
109     static uint64_t field_name (ElfParser *parser, gulong offset, gulong nth)   \
110     {                                                                   \
111         return GET_FIELD (parser, offset, Sym, nth, field_name);        \
112     }
113
114 MAKE_SYMBOL_ACCESSOR(st_name);
115 MAKE_SYMBOL_ACCESSOR(st_info);
116 MAKE_SYMBOL_ACCESSOR(st_value);
117 MAKE_SYMBOL_ACCESSOR(st_size);
118 MAKE_SYMBOL_ACCESSOR(st_shndx);
119
120 static void
121 section_free (Section *section)
122 {
123     g_free (section);
124 }
125
126 static const Section *
127 find_section (ElfParser *parser,
128               const char *name,
129               guint       type)
130 {
131     int i;
132     
133     for (i = 0; i < parser->n_sections; ++i)
134     {
135         Section *section = parser->sections[i];
136         
137         if (strcmp (section->name, name) == 0 && section->type == type)
138             return section;
139     }
140     
141     return NULL;
142 }
143
144 static gboolean
145 parse_elf_signature (const guchar *data,
146                      gsize         length,
147                      gboolean     *is_64,
148                      gboolean     *is_be)
149 {
150     /* FIXME: this function should be able to return an error */
151     if (length < EI_NIDENT)
152     {
153         /* FIXME set error */
154         return FALSE;
155     }
156     
157     if (data[EI_CLASS] != ELFCLASS32 &&
158         data[EI_CLASS] != ELFCLASS64)
159     {
160         /* FIXME set error */
161         return FALSE;
162     }
163     
164     if (data[EI_DATA] != ELFDATA2LSB &&
165         data[EI_DATA] != ELFDATA2MSB)
166     {
167         /* FIXME set error */
168         return FALSE;
169     }
170     
171     if (is_64)
172         *is_64 = (data[EI_CLASS] == ELFCLASS64);
173     
174     if (is_be)
175         *is_be = (data[EI_DATA] == ELFDATA2MSB);
176     
177     return TRUE;
178 }
179
180 ElfParser *
181 elf_parser_new_from_data (const guchar *data,
182                           gsize length)
183 {
184     ElfParser *parser;
185     gboolean is_64, is_big_endian;
186     int section_names_idx;
187     const guchar *section_names;
188     gsize section_headers;
189     int i;
190     
191     if (!parse_elf_signature (data, length, &is_64, &is_big_endian))
192     {
193         /* FIXME: set error */
194         return NULL;
195     }
196
197     parser = g_new0 (ElfParser, 1);
198
199     parser->is_64 = is_64;
200     parser->data = data;
201     parser->length = length;
202     
203 #if 0
204     g_print ("  new parser : %p\n", parser);
205 #endif
206     
207     /* Read ELF header */
208     
209     parser->n_sections = e_shnum (parser);
210     section_names_idx = e_shstrndx (parser);
211     section_headers = e_shoff (parser);
212     
213     /* Read section headers */
214     parser->sections = g_new0 (Section *, parser->n_sections);
215     
216     section_names = parser->data + sh_offset (parser, section_names_idx);
217
218     for (i = 0; i < parser->n_sections; ++i)
219     {
220         Section *section = g_new (Section, 1);
221     
222         section->name = (char *)(section_names + sh_name (parser, i));
223         section->size = sh_size (parser, i);
224         section->offset = sh_offset (parser, i);
225         section->allocated = !!(sh_flags (parser, i) & SHF_ALLOC);
226     
227         if (section->allocated)
228             section->load_address = sh_addr (parser, i);
229         else
230             section->load_address = 0;
231     
232         section->type = sh_type (parser, i);
233
234         parser->sections[i] = section;
235     }
236     
237     /* Cache the text section */
238     parser->text_section = find_section (parser, ".text", SHT_PROGBITS);
239     if (!parser->text_section)
240         parser->text_section = find_section (parser, ".text", SHT_NOBITS);
241
242     parser->filename = NULL;
243     parser->build_id = NULL;
244     
245     return parser;
246 }
247
248 ElfParser *
249 elf_parser_new (const char *filename,
250                 GError **err)
251 {
252     const guchar *data;
253     gsize length;
254     ElfParser *parser;
255
256     GMappedFile *file = g_mapped_file_new (filename, FALSE, NULL);
257     
258     if (!file)
259         return NULL;
260     
261 #if 0
262     g_print ("elf parser new : %s\n", filename);
263 #endif
264     
265     data = (guchar *)g_mapped_file_get_contents (file);
266     length = g_mapped_file_get_length (file);
267     
268 #if 0
269     g_print ("data %p: for %s\n", data, filename);
270 #endif
271     
272     parser = elf_parser_new_from_data (data, length);
273     
274 #if 0
275     g_print ("Parser for %s: %p\n", filename, parser);
276 #endif
277     
278     if (!parser)
279     {
280         g_mapped_file_free (file);
281         return NULL;
282     }
283
284     parser->filename = g_strdup (filename);
285     
286     parser->file = file;
287     
288 #if 0
289     g_print ("Elf file: %s  (debug: %s)\n",
290              filename, elf_parser_get_debug_link (parser, NULL));
291     
292     if (!parser->symbols)
293         g_print ("at this point %s has no symbols\n", filename);
294 #endif
295     
296     return parser;
297 }
298
299 guint32
300 elf_parser_get_crc32 (ElfParser *parser)
301 {
302     static const unsigned long crc32_table[256] = {
303         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
304         0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
305         0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
306         0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
307         0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
308         0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
309         0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
310         0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
311         0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
312         0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
313         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
314         0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
315         0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
316         0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
317         0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
318         0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
319         0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
320         0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
321         0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
322         0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
323         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
324         0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
325         0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
326         0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
327         0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
328         0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
329         0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
330         0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
331         0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
332         0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
333         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
334         0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
335         0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
336         0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
337         0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
338         0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
339         0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
340         0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
341         0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
342         0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
343         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
344         0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
345         0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
346     };
347     const guchar *data;
348     gsize length;
349     gulong crc;
350     gsize i;
351     
352     data = parser->data;
353     length = parser->length;
354     
355     crc = 0xffffffff;
356
357     madvise ((char *)data, length, MADV_SEQUENTIAL);
358     
359     for (i = 0; i < length; ++i)
360         crc = crc32_table[(crc ^ data[i]) & 0xff] ^ (crc >> 8);
361     
362     /* We just read the entire file into memory, but we only really
363      * need the symbol table, so swap the whole thing out.
364      *
365      * We could be more exact here, but it's only a few minor
366      * pagefaults.
367      */
368     if (parser->file)
369         madvise ((char *)data, length, MADV_DONTNEED);
370
371     return ~crc & 0xffffffff;
372 }
373
374 void
375 elf_parser_free (ElfParser *parser)
376 {
377     int i;
378     
379     for (i = 0; i < parser->n_sections; ++i)
380         section_free (parser->sections[i]);
381     g_free (parser->sections);
382     
383     if (parser->file)
384         g_mapped_file_free (parser->file);
385     
386     g_free (parser->symbols);
387     
388     if (parser->filename)
389         g_free (parser->filename);
390
391     if (parser->build_id)
392         g_free (parser->build_id);
393     
394     g_free (parser);
395 }
396
397 extern char *sysprof_cplus_demangle (const char *name, int options);
398
399 char *
400 elf_demangle (const char *name)
401 {
402 #define DMGL_PARAMS     (1 << 0)        /* Include function args */
403 #define DMGL_ANSI       (1 << 1)        /* Include const, volatile, etc */
404     
405     char *demangled = sysprof_cplus_demangle (name, DMGL_PARAMS | DMGL_ANSI);
406     
407     if (demangled)
408         return demangled;
409     else
410         return g_strdup (name);
411 }
412
413 /*
414  * Looking up symbols
415  */
416 static int
417 compare_sym (const void *a, const void *b)
418 {
419     const ElfSym *sym_a = a;
420     const ElfSym *sym_b = b;
421     
422     if (sym_a->address < sym_b->address)
423         return -1;
424     else if (sym_a->address == sym_b->address)
425         return 0;
426     else
427         return 1;
428 }
429
430 #if 0
431 static void
432 dump_symbols (ElfParser *parser, ElfSym *syms, guint n_syms)
433 {
434     int i;
435     
436     for (i = 0; i < n_syms; ++i)
437     {
438         ElfSym *s = &(syms[i]);
439         
440         g_print ("   %s: %lx\n", elf_parser_get_sym_name (parser, s), s->address);
441     }
442 }
443 #endif
444
445 static void
446 read_table (ElfParser *parser,
447             const Section *sym_table,
448             const Section *str_table)
449 {
450     int sym_size = GET_SIZE (parser, Sym);
451     int i, n_symbols;
452
453 #if 0
454     g_print ("elf: Reading table for %s\n", parser->filename? parser->filename : "<unknown>");
455 #endif
456     
457     parser->n_symbols = sym_table->size / sym_size;
458     parser->symbols = g_new (ElfSym, parser->n_symbols);
459     
460 #if 0
461     g_print ("sym table offset: %d\n", sym_table->offset);
462 #endif
463     
464     n_symbols = 0;
465 #if 0
466     g_print ("n syms: %d\n", parser->n_symbols);
467 #endif
468     for (i = 0; i < parser->n_symbols; ++i)
469     {
470         guint info;
471         gulong addr;
472         gulong shndx;
473
474         info = st_info (parser, sym_table->offset, i);
475         addr = st_value (parser, sym_table->offset, i);
476         shndx = st_shndx (parser, sym_table->offset, i);
477         
478 #if 0
479         g_print ("read symbol: %s (section: %d)\n", get_string_indirct (parser->parser,
480                                                                          parser->sym_format, "st_name",
481                                                                          str_table->offset),
482                  shndx);
483 #endif
484
485         if (addr != 0                                           &&
486             shndx < parser->n_sections                          &&
487             parser->sections[shndx] == parser->text_section     &&
488             (info & 0xf) == STT_FUNC                            &&
489             ((info >> 4) == STB_GLOBAL ||
490              (info >> 4) == STB_LOCAL  ||
491              (info >> 4) == STB_WEAK))
492         {
493             parser->symbols[n_symbols].address = addr;
494             parser->symbols[n_symbols].table = sym_table->offset;
495             parser->symbols[n_symbols].offset = i;
496
497             n_symbols++;
498             
499 #if 0
500             g_print ("    symbol: %s:   %lx\n",
501                      get_string_indirect (parser->parser,
502                                           parser->sym_format, "st_name",
503                                           str_table->offset),
504                      addr - parser->text_section->load_address);
505             g_print ("        sym %d in %p (info: %d:%d) (func:global  %d:%d)\n",
506                      addr, parser, info & 0xf, info >> 4, STT_FUNC, STB_GLOBAL);
507 #endif
508         }
509         else if (addr != 0)
510         {
511 #if 0
512             g_print ("        rejecting %d in %p (info: %d:%d) (func:global  %d:%d)\n",
513                      addr, parser, info & 0xf, info >> 4, STT_FUNC, STB_GLOBAL);
514 #endif
515         }
516     }
517     
518     parser->sym_strings = str_table->offset;
519     parser->n_symbols = n_symbols;
520
521     /* Allocate space for at least one symbol, so that parser->symbols will be
522      * non-NULL. If it ends up being NULL, we will be parsing the file over and
523      * over.
524      */
525     parser->symbols = g_renew (ElfSym, parser->symbols, parser->n_symbols + 1); 
526     
527     qsort (parser->symbols, parser->n_symbols, sizeof (ElfSym), compare_sym);
528 }
529
530 static void
531 read_symbols (ElfParser *parser)
532 {
533     const Section *symtab = find_section (parser, ".symtab", SHT_SYMTAB);
534     const Section *strtab = find_section (parser, ".strtab", SHT_STRTAB);
535     const Section *dynsym = find_section (parser, ".dynsym", SHT_DYNSYM);
536     const Section *dynstr = find_section (parser, ".dynstr", SHT_STRTAB);
537     
538     if (symtab && strtab)
539     {
540 #if 0
541         g_print ("reading symbol table of %s\n", parser->filename);
542 #endif
543         read_table (parser, symtab, strtab);
544     }
545     else if (dynsym && dynstr)
546     {
547 #if 0
548         g_print ("reading dynamic symbol table of %s\n", parser->filename);
549 #endif
550         read_table (parser, dynsym, dynstr);
551     }
552     else
553     {
554         /* To make sure parser->symbols is non-NULL */
555         parser->n_symbols = 0;
556         parser->symbols = g_new (ElfSym, 1);
557     }
558 }
559
560 static ElfSym *
561 do_lookup (ElfSym *symbols,
562            gulong  address,
563            int     first,
564            int     last)
565 {
566     if (address >= symbols[last].address)
567     {
568         return &(symbols[last]);
569     }
570     else if (last - first < 3)
571     {
572         while (last >= first)
573         {
574             if (address >= symbols[last].address)
575                 return &(symbols[last]);
576             
577             last--;
578         }
579         
580         return NULL;
581     }
582     else
583     {
584         int mid = (first + last) / 2;
585         
586         if (symbols[mid].address > address)
587             return do_lookup (symbols, address, first, mid);
588         else
589             return do_lookup (symbols, address, mid, last);
590     }
591 }
592
593 /* Address should be given in 'offset into text segment' */
594 const ElfSym *
595 elf_parser_lookup_symbol (ElfParser *parser,
596                           gulong     address)
597 {
598     const ElfSym *result;
599     
600     if (!parser->symbols)
601     {
602 #if 0
603         g_print ("reading symbols at %p\n", parser);
604 #endif
605         read_symbols (parser);
606     }
607     
608     if (parser->n_symbols == 0)
609         return NULL;
610     
611     if (!parser->text_section)
612         return NULL;
613     
614     address += parser->text_section->load_address;
615
616 #if 0
617     g_print ("elf: the address we are looking up is %p\n", address);
618 #endif
619     
620     result = do_lookup (parser->symbols, address, 0, parser->n_symbols - 1);
621     
622 #if 0
623     if (result)
624     {
625         g_print ("  elf: found %s at %lx\n", elf_parser_get_sym_name (parser, result), result->address);
626     }
627     else
628     {
629         g_print ("elf: not found\n");
630     }
631 #endif
632     
633     if (result)
634     {
635         gulong size = st_size (parser, result->table, result->offset);
636
637         if (size > 0 && result->address + size <= address)
638         {
639 #if 0
640             g_print ("  elf: ends at %lx, so rejecting\n",
641                      result->address + size);
642 #endif
643             result = NULL;
644         }
645     }
646     
647     if (result)
648     {
649         /* Reject the symbols if the address is outside the text section */
650         if (address > parser->text_section->load_address + parser->text_section->size)
651             result = NULL;
652     }
653
654     return result;
655 }
656
657 gulong
658 elf_parser_get_text_offset (ElfParser *parser)
659 {
660     g_return_val_if_fail (parser != NULL, (gulong)-1);
661     
662     if (!parser->text_section)
663         return (gulong)-1;
664     
665     return parser->text_section->offset;
666 }
667
668 static gchar *
669 make_hex_string (const guchar *data, int n_bytes)
670 {
671     static const char hex_digits[] = {
672         '0', '1', '2', '3', '4', '5', '6', '7',
673         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
674     };
675     GString *string = g_string_new (NULL);
676     int i;
677     
678     for (i = 0; i < n_bytes; ++i)
679     {
680         char c = data[i];
681             
682         g_string_append_c (string, hex_digits[(c & 0xf0) >> 4]);
683         g_string_append_c (string, hex_digits[(c & 0x0f)]);
684     }
685
686     return g_string_free (string, FALSE);
687 }
688         
689 const gchar *
690 elf_parser_get_build_id (ElfParser *parser)
691 {
692     if (!parser->checked_build_id)
693     {
694         const Section *build_id =
695             find_section (parser, ".note.gnu.build-id", SHT_NOTE);
696         guint64 name_size;
697         guint64 desc_size;
698         guint64 type;
699         const char *name;
700         guint64 offset;
701             
702         parser->checked_build_id = TRUE;
703
704         if (!build_id)
705             return NULL;
706
707         offset = build_id->offset;
708
709         name_size = GET_FIELD (parser, offset, Nhdr, 0, n_namesz);
710         desc_size = GET_FIELD (parser, offset, Nhdr, 0, n_descsz);
711         type      = GET_FIELD (parser, offset, Nhdr, 0, n_type);
712
713         offset += GET_SIZE (parser, Nhdr);
714
715         name = (char *)(parser->data + offset);
716         
717         if (strncmp (name, ELF_NOTE_GNU, name_size) != 0 || type != NT_GNU_BUILD_ID)
718             return NULL;
719
720         offset += strlen (name);
721
722         offset = (offset + 3) & (~0x3);
723
724         parser->build_id = make_hex_string (parser->data + offset, desc_size);
725     }
726     
727     return parser->build_id;
728 }
729
730 const char *
731 elf_parser_get_debug_link (ElfParser *parser, guint32 *crc32)
732 {
733     guint64 offset;
734     const Section *debug_link = find_section (parser, ".gnu_debuglink",
735                                               SHT_PROGBITS);
736     const gchar *result;
737     
738     if (!debug_link)
739         return NULL;
740
741     offset = debug_link->offset;
742     
743     result = (char *)(parser->data + offset);
744
745     if (crc32)
746     {
747         int len = strlen (result) + 1;
748         offset = (offset + len + 3) & ~0x3;
749
750         *crc32 = GET_UINT32 (parser, offset);
751     }
752     
753     return result;
754 }
755
756 const guchar *
757 get_section (ElfParser *parser,
758              const char *name)
759 {
760     const Section *section = find_section (parser, name, SHT_PROGBITS);
761
762     if (section)
763         return parser->data + section->offset;
764     else
765         return NULL;
766 }
767
768 const guchar *
769 elf_parser_get_eh_frame   (ElfParser   *parser)
770 {
771     return get_section (parser, ".eh_frame");
772 }
773
774 const guchar *
775 elf_parser_get_debug_frame   (ElfParser   *parser)
776 {
777     return get_section (parser, ".debug_frame");
778 }
779
780 const char *
781 elf_parser_get_sym_name (ElfParser *parser,
782                          const ElfSym *sym)
783 {
784     g_return_val_if_fail (parser != NULL, NULL);
785
786     return (char *)(parser->data + parser->sym_strings +
787                     st_name (parser, sym->table, sym->offset));
788 }
789
790 gboolean
791 elf_parser_owns_symbol (ElfParser *parser,
792                         const ElfSym *sym)
793 {
794     ElfSym *first, *last;
795     
796     if (!parser->n_symbols)
797         return FALSE;
798
799     first = parser->symbols;
800     last = parser->symbols + parser->n_symbols - 1;
801
802     return first <= sym && sym <= last;
803 }
804
805 gulong
806 elf_parser_get_sym_address (ElfParser *parser,
807                             const ElfSym *sym)
808 {
809     return sym->address - parser->text_section->load_address;
810 }
811
812 /*
813  * Utility functions
814  */