2 /* Extract debug lines info from an ELF binary stab section */
5 * Adam: Note, this file works on 32-bit files only.
15 #include <sys/types.h>
20 #define LIN_PER_PAGE (PAGESIZE/sizeof(Stab_entry))
24 unsigned int n_strx; /* index into string table of name */
25 unsigned char n_type; /* type of symbol */
26 unsigned char n_other; /* misc info (usually empty) */
27 unsigned short n_desc; /* description field */
28 unsigned int n_value; /* value of symbol */
29 } __attribute__ ((packed)) Stab_entry;
35 } __attribute__ ((packed)) Stab_line;
37 const unsigned str_max = MAX_PAGES*PAGESIZE;
38 const unsigned lin_max = MAX_PAGES*PAGESIZE/sizeof(Stab_line);
40 static char *str_field;
41 static Stab_line *lin_field;
42 static unsigned str_end;
43 static unsigned lin_end;
44 static unsigned func_offset;
48 elf_sh_lookup(unsigned char *elf_image, int n)
50 Elf32_Ehdr *ehdr = (Elf32_Ehdr*)elf_image;
52 return (n < ehdr->e_shnum)
53 ? (Elf32_Shdr*)(elf_image + ehdr->e_shoff + n*ehdr->e_shentsize)
58 search_str(const char *str, unsigned len, unsigned *idx)
60 const char *c_next, *c, *d;
62 if (!str_field || !*str_field)
65 for (c_next=str_field; ; )
68 for (; *c_next; c_next++)
72 for (c=c_next, d=str+len; d>=str && (*c == *d); c--, d--)
78 // found (could be a substring)
82 // test for end-of-field
84 // end of field -- not found
90 add_str(const char *str, unsigned len, unsigned *idx)
92 // if still included, don't include anymore
93 if (search_str(str, len, idx))
96 // check if str_field is big enough
97 if (str_end+len+1 >= str_max)
99 fprintf(stderr, "Not enough memory for debug lines (str space)\n");
105 // add string to end of str_field
106 strcpy(str_field+str_end, str);
109 // terminate string field
110 str_field[str_end] = '\0';
115 // see documentation in "info stabs"
117 add_entry(const Stab_entry *se, const char *se_str)
119 const char *se_name = se_str + se->n_strx;
120 int se_name_len = strlen(se_name);
121 unsigned se_name_idx = 0;
124 && ((se->n_type == 0x64) || (se->n_type == 0x84)))
126 if (!add_str(se_name, se_name_len, &se_name_idx))
130 if (lin_end >= lin_max)
132 fprintf(stderr, "Not enough temporary memory for lines (lin space)\n");
138 case 0x24: // N_FUN: function name
139 func_offset = se->n_value; // start address of function
142 case 0x44: // N_SLINE: line number in text segment
143 if (have_func && (se->n_desc < 0xfffd)) // sanity check
145 // Search last SLINE entry and compare addresses. If they are
146 // same, overwrite the last entry because we display only one
147 // line number per address
148 unsigned addr = se->n_value + func_offset;
150 unsigned l = lin_end;
151 while ((l > 0) && (lin_field[l-1].line>=0xfffd))
154 if ((l > 0) && (lin_field[l-1].addr == addr))
156 // found, delete array entry
159 lin_field[l-1] = lin_field[l];
165 lin_field[lin_end].addr = addr;
166 lin_field[lin_end].line = se->n_desc;
170 case 0x64: // N_SO: main file name / directory
173 if (lin_end>0 && lin_field[lin_end-1].line == 0xffff)
175 // mark last entry as directory, this is a file name
176 lin_field[lin_end-1].line = 0xfffe;
182 case 0x84: // N_SOL: name of include file
186 char c = se_name[se_name_len-1];
188 if (c=='h' || c=='H')
189 type = 0xfffd; // mark as header file
191 lin_field[lin_end].addr = se_name_idx;
192 lin_field[lin_end].line = type;
202 add_section(const Stab_entry *se, const char *str, unsigned n)
210 if (!add_entry(se++, str))
217 extract_lines(unsigned char *elf_image)
219 Elf32_Ehdr *ehdr = (Elf32_Ehdr*)elf_image;
220 Elf32_Shdr *sh_sym, *sh_str;
224 // search contiguous free pages for temporary memory
225 str_end = lin_end = 0;
226 lin_field = (Stab_line*)malloc(lin_max);
227 str_field = (char*)malloc(str_max);
231 if (ehdr->e_shstrndx == SHN_UNDEF)
233 fprintf(stderr, "Error in ELF header\n");
237 if (0 == (sh_str = elf_sh_lookup(elf_image, ehdr->e_shstrndx)))
239 fprintf(stderr, "Error in ELF stab section\n");
243 strtab = (const char*)(elf_image + sh_str->sh_offset);
245 for (i=0; i<ehdr->e_shnum; i++)
247 sh_sym = elf_sh_lookup(elf_image, i);
248 if ( ( sh_sym->sh_type == SHT_PROGBITS
249 || sh_sym->sh_type == SHT_STRTAB)
250 && (!strcmp(sh_sym->sh_name + strtab, ".stab")))
252 if (0 == (sh_str = elf_sh_lookup(elf_image, sh_sym->sh_link)))
254 fprintf(stderr, "Error in ELF stab section\n");
258 if (!add_section((const Stab_entry*)(elf_image+sh_sym->sh_offset),
259 (const char*) (elf_image+sh_str->sh_offset),
260 sh_sym->sh_size/sh_sym->sh_entsize))
267 // add terminating entry
268 if (lin_end >= lin_max)
270 fprintf(stderr, "Not enough temporary memory for lines "
271 "(terminating line entry)\n");
274 lin_field[lin_end].addr = 0;
275 lin_field[lin_end].line = 0;
278 // string offset relativ to begin of lines
279 for (i=0; i<lin_end; i++)
280 if (lin_field[i].line >= 0xfffd)
281 lin_field[i].addr += lin_end*sizeof(Stab_line);
283 fwrite(lin_field, lin_end*sizeof(Stab_line), 1, stdout);
284 fwrite(str_field, str_end, 1, stdout);
289 fprintf(stderr, "No lines stored\n");
294 main(int argc, char **argv)
298 unsigned char *image;
302 fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
306 if ((fd = open(argv[1], O_RDONLY)) < 0)
308 fprintf(stderr, "Cannot open %s\n", argv[1]);
312 size = lseek(fd, 0, SEEK_END);
314 if ((image = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0))
315 == (unsigned char*)-1)
317 fprintf(stderr, "Cannot map ELF file\n");
321 return extract_lines(image);