]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/genlines.c
c20bce76d0c051f4996f614e9e1f8451cac8ca8b
[l4.git] / kernel / fiasco / src / kern / genlines.c
1
2 /* Extract debug lines info from an ELF binary stab section */
3
4 /*
5  * Adam: Note, this file works on 32-bit files only.
6  */
7
8 #include <stdio.h>
9 #include <elf.h>
10 #include <fcntl.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/mman.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17
18 #define PAGESIZE                4096
19 #define MAX_PAGES               512
20 #define LIN_PER_PAGE            (PAGESIZE/sizeof(Stab_entry))
21
22 typedef struct 
23 {
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;
30
31 typedef struct
32 {
33   unsigned int  addr;
34   unsigned short line;
35 } __attribute__ ((packed)) Stab_line;
36
37 const unsigned str_max = MAX_PAGES*PAGESIZE;
38 const unsigned lin_max = MAX_PAGES*PAGESIZE/sizeof(Stab_line);
39
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;
45 static int have_func;
46
47 static Elf32_Shdr*
48 elf_sh_lookup(unsigned char *elf_image, int n)
49 {
50   Elf32_Ehdr *ehdr = (Elf32_Ehdr*)elf_image;
51
52   return (n < ehdr->e_shnum)
53     ? (Elf32_Shdr*)(elf_image + ehdr->e_shoff + n*ehdr->e_shentsize)
54     : 0;
55 }
56
57 static int
58 search_str(const char *str, unsigned len, unsigned *idx)
59 {
60   const char *c_next, *c, *d;
61
62   if (!str_field || !*str_field)
63     return 0;
64
65   for (c_next=str_field; ; )
66     {
67       // goto end of string
68       for (; *c_next; c_next++)
69         ;
70
71       // compare strings
72       for (c=c_next, d=str+len; d>=str && (*c == *d); c--, d--)
73         ;
74       
75       if (d<str)
76         {
77           *idx = c+1-str_field;
78           // found (could be a substring)
79           return 1;
80         }
81
82       // test for end-of-field
83       if (!*++c_next)
84         // end of field -- not found
85         return 0;
86     }
87 }
88
89 static int
90 add_str(const char *str, unsigned len, unsigned *idx)
91 {
92   // if still included, don't include anymore
93   if (search_str(str, len, idx))
94     return 1;
95
96   // check if str_field is big enough
97   if (str_end+len+1 >= str_max)
98     {
99       fprintf(stderr, "Not enough memory for debug lines (str space)\n");
100       return 0;
101     }
102
103   *idx = str_end;
104   
105   // add string to end of str_field
106   strcpy(str_field+str_end, str);
107   str_end += len+1;
108
109   // terminate string field
110   str_field[str_end] = '\0';
111
112   return 1;
113 }
114
115 // see documentation in "info stabs"
116 static int
117 add_entry(const Stab_entry *se, const char *se_str)
118 {
119   const char *se_name = se_str + se->n_strx;
120   int se_name_len = strlen(se_name);
121   unsigned se_name_idx = 0;
122
123   if (se_name_len
124       && ((se->n_type == 0x64) || (se->n_type == 0x84)))
125     {
126       if (!add_str(se_name, se_name_len, &se_name_idx))
127         return 0;
128     }
129
130   if (lin_end >= lin_max)
131     {
132       fprintf(stderr, "Not enough temporary memory for lines (lin space)\n");
133       return 0;
134     }
135  
136   switch (se->n_type)
137     {
138     case 0x24: // N_FUN: function name
139       func_offset = se->n_value;                // start address of function
140       have_func   = 1;
141       break;
142     case 0x44: // N_SLINE: line number in text segment
143       if (have_func && (se->n_desc < 0xfffd)) // sanity check
144         {
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;
149
150           unsigned l = lin_end;
151           while ((l > 0) && (lin_field[l-1].line>=0xfffd))
152             l--;
153           
154           if ((l > 0) && (lin_field[l-1].addr == addr))
155             {
156               // found, delete array entry
157               while (l < lin_end)
158                 {
159                   lin_field[l-1] = lin_field[l];
160                   l++;
161                 }
162               lin_end--;
163             }
164           // append
165           lin_field[lin_end].addr = addr;
166           lin_field[lin_end].line = se->n_desc;
167           lin_end++;
168         }
169       break;
170     case 0x64: // N_SO: main file name / directory
171       if (se_name_len)
172         {
173           if (lin_end>0 && lin_field[lin_end-1].line == 0xffff)
174             {
175               // mark last entry as directory, this is a file name
176               lin_field[lin_end-1].line = 0xfffe;
177             }
178         }
179       else
180         have_func = 0;
181       // fall through
182     case 0x84: // N_SOL: name of include file
183       if (se_name_len)
184         {
185           int type = 0xffff;
186           char c = se_name[se_name_len-1];
187           
188           if (c=='h' || c=='H')
189             type = 0xfffd; // mark as header file
190           
191           lin_field[lin_end].addr = se_name_idx;
192           lin_field[lin_end].line = type;
193           lin_end++;
194         }
195       break;
196     }
197
198   return 1;
199 }
200
201 static int
202 add_section(const Stab_entry *se, const char *str, unsigned n)
203 {
204   unsigned int i;
205
206   func_offset = 0;
207   have_func   = 0;
208
209   for (i=0; i<n; i++)
210     if (!add_entry(se++, str))
211       return 0;
212
213   return 1;
214 }
215
216 int
217 extract_lines(unsigned char *elf_image) 
218 {
219   Elf32_Ehdr *ehdr = (Elf32_Ehdr*)elf_image;
220   Elf32_Shdr *sh_sym, *sh_str;
221   const char *strtab;
222   unsigned int i;
223
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);
228
229   str_field[0] = '\0';
230
231   if (ehdr->e_shstrndx == SHN_UNDEF)
232     {
233       fprintf(stderr, "Error in ELF header\n");
234       return -3;
235     }
236
237   if (0 == (sh_str = elf_sh_lookup(elf_image, ehdr->e_shstrndx)))
238     {
239       fprintf(stderr, "Error in ELF stab section\n");
240       return -3;
241     }
242
243   strtab = (const char*)(elf_image + sh_str->sh_offset);
244
245   for (i=0; i<ehdr->e_shnum; i++)
246     {
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")))
251         {
252           if (0 == (sh_str = elf_sh_lookup(elf_image, sh_sym->sh_link)))
253             {
254               fprintf(stderr, "Error in ELF stab section\n");
255               return -3;
256             }
257
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))
261             return -3;
262         }
263     }
264
265   if (lin_end > 0)
266     {
267       // add terminating entry
268       if (lin_end >= lin_max)
269         {
270           fprintf(stderr, "Not enough temporary memory for lines "
271                           "(terminating line entry)\n");
272           return -3;
273         }
274       lin_field[lin_end].addr = 0;
275       lin_field[lin_end].line = 0;
276       lin_end++;
277
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);
282
283       fwrite(lin_field, lin_end*sizeof(Stab_line), 1, stdout);
284       fwrite(str_field, str_end, 1, stdout);
285
286       return 0;
287     }
288
289   fprintf(stderr, "No lines stored\n");
290   return -3;
291 }
292
293 int
294 main(int argc, char **argv)
295 {
296   int fd;
297   unsigned size;
298   unsigned char *image;
299
300   if (argc != 2)
301     {
302       fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
303       return -1;
304     }
305
306   if ((fd = open(argv[1], O_RDONLY)) < 0)
307     {
308       fprintf(stderr, "Cannot open %s\n", argv[1]);
309       return -2;
310     }
311
312   size = lseek(fd, 0, SEEK_END);
313
314   if ((image = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0)) 
315       == (unsigned char*)-1)
316     {
317       fprintf(stderr, "Cannot map ELF file\n");
318       return -3;
319     }
320
321   return extract_lines(image);
322 }
323