1 /* Sysprof -- Sampling, systemwide CPU profiler
2 * Copyright 2006, 2007, Soeren Sandmann
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.
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.
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.
22 #include "elfparser.h"
24 typedef struct Section Section;
60 gboolean checked_build_id;
63 const Section * text_section;
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
70 #define GET_FIELD(parser, offset, struct_name, idx, field_name) \
72 ((Elf64_ ## struct_name *)(((parser)->data + offset)) + (idx))->field_name : \
73 ((Elf32_ ## struct_name *)(((parser)->data + offset)) + (idx))->field_name)
75 #define GET_UINT32(parser, offset) \
76 *((uint32_t *)(parser->data + offset)) \
78 #define GET_SIZE(parser, struct_name) \
80 sizeof (Elf64_ ## struct_name) : \
81 sizeof (Elf32_ ## struct_name)))
83 #define MAKE_ELF_UINT_ACCESSOR(field_name) \
84 static uint64_t field_name (ElfParser *parser) \
86 return GET_FIELD (parser, 0, Ehdr, 0, field_name); \
89 MAKE_ELF_UINT_ACCESSOR (e_shoff)
90 MAKE_ELF_UINT_ACCESSOR (e_shnum)
91 MAKE_ELF_UINT_ACCESSOR (e_shstrndx)
93 #define MAKE_SECTION_HEADER_ACCESSOR(field_name) \
94 static uint64_t field_name (ElfParser *parser, int nth_section) \
96 gsize offset = e_shoff (parser); \
98 return GET_FIELD (parser, offset, Shdr, nth_section, field_name); \
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);
108 #define MAKE_SYMBOL_ACCESSOR(field_name) \
109 static uint64_t field_name (ElfParser *parser, gulong offset, gulong nth) \
111 return GET_FIELD (parser, offset, Sym, nth, field_name); \
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);
121 section_free (Section *section)
126 static const Section *
127 find_section (ElfParser *parser,
133 for (i = 0; i < parser->n_sections; ++i)
135 Section *section = parser->sections[i];
137 if (strcmp (section->name, name) == 0 && section->type == type)
145 parse_elf_signature (const guchar *data,
150 /* FIXME: this function should be able to return an error */
151 if (length < EI_NIDENT)
153 /* FIXME set error */
157 if (data[EI_CLASS] != ELFCLASS32 &&
158 data[EI_CLASS] != ELFCLASS64)
160 /* FIXME set error */
164 if (data[EI_DATA] != ELFDATA2LSB &&
165 data[EI_DATA] != ELFDATA2MSB)
167 /* FIXME set error */
172 *is_64 = (data[EI_CLASS] == ELFCLASS64);
175 *is_be = (data[EI_DATA] == ELFDATA2MSB);
181 elf_parser_new_from_data (const guchar *data,
185 gboolean is_64, is_big_endian;
186 int section_names_idx;
187 const guchar *section_names;
188 gsize section_headers;
191 if (!parse_elf_signature (data, length, &is_64, &is_big_endian))
193 /* FIXME: set error */
197 parser = g_new0 (ElfParser, 1);
199 parser->is_64 = is_64;
201 parser->length = length;
204 g_print (" new parser : %p\n", parser);
207 /* Read ELF header */
209 parser->n_sections = e_shnum (parser);
210 section_names_idx = e_shstrndx (parser);
211 section_headers = e_shoff (parser);
213 /* Read section headers */
214 parser->sections = g_new0 (Section *, parser->n_sections);
216 section_names = parser->data + sh_offset (parser, section_names_idx);
218 for (i = 0; i < parser->n_sections; ++i)
220 Section *section = g_new (Section, 1);
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);
227 if (section->allocated)
228 section->load_address = sh_addr (parser, i);
230 section->load_address = 0;
232 section->type = sh_type (parser, i);
234 parser->sections[i] = section;
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);
242 parser->filename = NULL;
243 parser->build_id = NULL;
249 elf_parser_new (const char *filename,
256 GMappedFile *file = g_mapped_file_new (filename, FALSE, NULL);
262 g_print ("elf parser new : %s\n", filename);
265 data = (guchar *)g_mapped_file_get_contents (file);
266 length = g_mapped_file_get_length (file);
269 g_print ("data %p: for %s\n", data, filename);
272 parser = elf_parser_new_from_data (data, length);
275 g_print ("Parser for %s: %p\n", filename, parser);
280 g_mapped_file_free (file);
284 parser->filename = g_strdup (filename);
289 g_print ("Elf file: %s (debug: %s)\n",
290 filename, elf_parser_get_debug_link (parser, NULL));
292 if (!parser->symbols)
293 g_print ("at this point %s has no symbols\n", filename);
300 elf_parser_get_crc32 (ElfParser *parser)
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
353 length = parser->length;
357 madvise ((char *)data, length, MADV_SEQUENTIAL);
359 for (i = 0; i < length; ++i)
360 crc = crc32_table[(crc ^ data[i]) & 0xff] ^ (crc >> 8);
362 /* We just read the entire file into memory, but we only really
363 * need the symbol table, so swap the whole thing out.
365 * We could be more exact here, but it's only a few minor
369 madvise ((char *)data, length, MADV_DONTNEED);
371 return ~crc & 0xffffffff;
375 elf_parser_free (ElfParser *parser)
379 for (i = 0; i < parser->n_sections; ++i)
380 section_free (parser->sections[i]);
381 g_free (parser->sections);
384 g_mapped_file_free (parser->file);
386 g_free (parser->symbols);
388 if (parser->filename)
389 g_free (parser->filename);
391 if (parser->build_id)
392 g_free (parser->build_id);
397 extern char *sysprof_cplus_demangle (const char *name, int options);
400 elf_demangle (const char *name)
402 #define DMGL_PARAMS (1 << 0) /* Include function args */
403 #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
405 char *demangled = sysprof_cplus_demangle (name, DMGL_PARAMS | DMGL_ANSI);
410 return g_strdup (name);
417 compare_sym (const void *a, const void *b)
419 const ElfSym *sym_a = a;
420 const ElfSym *sym_b = b;
422 if (sym_a->address < sym_b->address)
424 else if (sym_a->address == sym_b->address)
432 dump_symbols (ElfParser *parser, ElfSym *syms, guint n_syms)
436 for (i = 0; i < n_syms; ++i)
438 ElfSym *s = &(syms[i]);
440 g_print (" %s: %lx\n", elf_parser_get_sym_name (parser, s), s->address);
446 read_table (ElfParser *parser,
447 const Section *sym_table,
448 const Section *str_table)
450 int sym_size = GET_SIZE (parser, Sym);
454 g_print ("elf: Reading table for %s\n", parser->filename? parser->filename : "<unknown>");
457 parser->n_symbols = sym_table->size / sym_size;
458 parser->symbols = g_new (ElfSym, parser->n_symbols);
461 g_print ("sym table offset: %d\n", sym_table->offset);
466 g_print ("n syms: %d\n", parser->n_symbols);
468 for (i = 0; i < parser->n_symbols; ++i)
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);
479 g_print ("read symbol: %s (section: %d)\n", get_string_indirct (parser->parser,
480 parser->sym_format, "st_name",
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))
493 parser->symbols[n_symbols].address = addr;
494 parser->symbols[n_symbols].table = sym_table->offset;
495 parser->symbols[n_symbols].offset = i;
500 g_print (" symbol: %s: %lx\n",
501 get_string_indirect (parser->parser,
502 parser->sym_format, "st_name",
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);
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);
518 parser->sym_strings = str_table->offset;
519 parser->n_symbols = n_symbols;
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
525 parser->symbols = g_renew (ElfSym, parser->symbols, parser->n_symbols + 1);
527 qsort (parser->symbols, parser->n_symbols, sizeof (ElfSym), compare_sym);
531 read_symbols (ElfParser *parser)
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);
538 if (symtab && strtab)
541 g_print ("reading symbol table of %s\n", parser->filename);
543 read_table (parser, symtab, strtab);
545 else if (dynsym && dynstr)
548 g_print ("reading dynamic symbol table of %s\n", parser->filename);
550 read_table (parser, dynsym, dynstr);
554 /* To make sure parser->symbols is non-NULL */
555 parser->n_symbols = 0;
556 parser->symbols = g_new (ElfSym, 1);
561 do_lookup (ElfSym *symbols,
566 if (address >= symbols[last].address)
568 return &(symbols[last]);
570 else if (last - first < 3)
572 while (last >= first)
574 if (address >= symbols[last].address)
575 return &(symbols[last]);
584 int mid = (first + last) / 2;
586 if (symbols[mid].address > address)
587 return do_lookup (symbols, address, first, mid);
589 return do_lookup (symbols, address, mid, last);
593 /* Address should be given in 'offset into text segment' */
595 elf_parser_lookup_symbol (ElfParser *parser,
598 const ElfSym *result;
600 if (!parser->symbols)
603 g_print ("reading symbols at %p\n", parser);
605 read_symbols (parser);
608 if (parser->n_symbols == 0)
611 if (!parser->text_section)
614 address += parser->text_section->load_address;
617 g_print ("elf: the address we are looking up is %p\n", address);
620 result = do_lookup (parser->symbols, address, 0, parser->n_symbols - 1);
625 g_print (" elf: found %s at %lx\n", elf_parser_get_sym_name (parser, result), result->address);
629 g_print ("elf: not found\n");
635 gulong size = st_size (parser, result->table, result->offset);
637 if (size > 0 && result->address + size <= address)
640 g_print (" elf: ends at %lx, so rejecting\n",
641 result->address + size);
649 /* Reject the symbols if the address is outside the text section */
650 if (address > parser->text_section->load_address + parser->text_section->size)
658 elf_parser_get_text_offset (ElfParser *parser)
660 g_return_val_if_fail (parser != NULL, (gulong)-1);
662 if (!parser->text_section)
665 return parser->text_section->offset;
669 make_hex_string (const guchar *data, int n_bytes)
671 static const char hex_digits[] = {
672 '0', '1', '2', '3', '4', '5', '6', '7',
673 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
675 GString *string = g_string_new (NULL);
678 for (i = 0; i < n_bytes; ++i)
682 g_string_append_c (string, hex_digits[(c & 0xf0) >> 4]);
683 g_string_append_c (string, hex_digits[(c & 0x0f)]);
686 return g_string_free (string, FALSE);
690 elf_parser_get_build_id (ElfParser *parser)
692 if (!parser->checked_build_id)
694 const Section *build_id =
695 find_section (parser, ".note.gnu.build-id", SHT_NOTE);
702 parser->checked_build_id = TRUE;
707 offset = build_id->offset;
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);
713 offset += GET_SIZE (parser, Nhdr);
715 name = (char *)(parser->data + offset);
717 if (strncmp (name, ELF_NOTE_GNU, name_size) != 0 || type != NT_GNU_BUILD_ID)
720 offset += strlen (name);
722 offset = (offset + 3) & (~0x3);
724 parser->build_id = make_hex_string (parser->data + offset, desc_size);
727 return parser->build_id;
731 elf_parser_get_debug_link (ElfParser *parser, guint32 *crc32)
734 const Section *debug_link = find_section (parser, ".gnu_debuglink",
741 offset = debug_link->offset;
743 result = (char *)(parser->data + offset);
747 int len = strlen (result) + 1;
748 offset = (offset + len + 3) & ~0x3;
750 *crc32 = GET_UINT32 (parser, offset);
757 get_section (ElfParser *parser,
760 const Section *section = find_section (parser, name, SHT_PROGBITS);
763 return parser->data + section->offset;
769 elf_parser_get_eh_frame (ElfParser *parser)
771 return get_section (parser, ".eh_frame");
775 elf_parser_get_debug_frame (ElfParser *parser)
777 return get_section (parser, ".debug_frame");
781 elf_parser_get_sym_name (ElfParser *parser,
784 g_return_val_if_fail (parser != NULL, NULL);
786 return (char *)(parser->data + parser->sym_strings +
787 st_name (parser, sym->table, sym->offset));
791 elf_parser_owns_symbol (ElfParser *parser,
794 ElfSym *first, *last;
796 if (!parser->n_symbols)
799 first = parser->symbols;
800 last = parser->symbols + parser->n_symbols - 1;
802 return first <= sym && sym <= last;
806 elf_parser_get_sym_address (ElfParser *parser,
809 return sym->address - parser->text_section->load_address;