]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_debuginfo/readstabs.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / coregrind / m_debuginfo / readstabs.c
1
2 /*--------------------------------------------------------------------*/
3 /*--- Read stabs debug info.                           readstabs.c ---*/
4 /*--------------------------------------------------------------------*/
5
6 /*
7    This file is part of Valgrind, a dynamic binary instrumentation
8    framework.
9
10    Copyright (C) 2000-2010 Julian Seward
11       jseward@acm.org
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of the
16    License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful, but
19    WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26    02111-1307, USA.
27
28    The GNU General Public License is contained in the file COPYING.
29 */
30
31 #if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_l4re)
32
33 /*
34    Stabs reader greatly improved by Nick Nethercote, Apr 02.
35    This module was also extensively hacked on by Jeremy Fitzhardinge
36    and Tom Hughes.
37 */
38
39 #include "pub_core_basics.h"
40 #include "pub_core_debuginfo.h"
41 #include "pub_core_libcbase.h"
42 #include "pub_core_libcassert.h"
43 #include "pub_core_libcprint.h"
44 #include "pub_core_xarray.h"
45 #include "priv_misc.h"             /* dinfo_zalloc/free/strdup */
46 #include "priv_tytypes.h"
47 #include "priv_d3basics.h"
48 #include "priv_storage.h"
49 #include "priv_readstabs.h"        /* self */
50
51 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
52 #if defined(VGO_linux)
53 #  include <a.out.h> /* stabs defns */
54 #elif defined(VGO_darwin)
55 #  include <mach-o/nlist.h>
56 #  define n_other n_sect
57 #  if VG_WORDSIZE == 8
58 #     define nlist nlist_64
59 #  endif
60 #elif defined(VGO_l4re)
61 struct nlist {
62         union {
63                 char *n_name;
64                 struct nlist *n_next;
65                 long n_strx;
66         } n_un;
67         unsigned char n_type;
68         char n_other;
69         short n_desc;
70         unsigned long n_value;
71 };
72 #else
73 #  error "Unknown OS"
74 #endif
75 /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
76
77 /*------------------------------------------------------------*/
78 /*--- Read STABS format debug info.                        ---*/
79 /*------------------------------------------------------------*/
80
81 /* Stabs entry types, from:
82  *   The "stabs" debug format
83  *   Menapace, Kingdon and MacKenzie
84  *   Cygnus Support
85  */
86 typedef enum { N_UNDEF = 0,     /* undefined symbol, new stringtab  */
87                N_GSYM  = 32,    /* Global symbol                    */
88                N_FUN   = 36,    /* Function start or end            */
89                N_STSYM = 38,    /* Data segment file-scope variable */
90                N_LCSYM = 40,    /* BSS segment file-scope variable  */
91                N_RSYM  = 64,    /* Register variable                */
92                N_SLINE = 68,    /* Source line number               */
93                N_SO    = 100,   /* Source file path and name        */
94                N_LSYM  = 128,   /* Stack variable or type           */
95                N_BINCL = 130,   /* Beginning of an include file     */
96                N_SOL   = 132,   /* Include file name                */
97                N_PSYM  = 160,   /* Function parameter               */
98                N_EINCL = 162,   /* End of an include file           */
99                N_LBRAC = 192,   /* Start of lexical block           */
100                N_EXCL  = 194,   /* Placeholder for an include file  */
101                N_RBRAC = 224    /* End   of lexical block           */
102              } stab_types;
103       
104
105 /* Read stabs-format debug info.  This is all rather horrible because
106    stabs is a underspecified, kludgy hack.
107 */
108 void ML_(read_debuginfo_stabs) ( DebugInfo* di,
109                                  UChar* stabC,   Int stab_sz, 
110                                  UChar* stabstr, Int stabstr_sz )
111 {
112    const Bool debug     = False;
113    const Bool contdebug = False;
114    Int    i;
115    Int    n_stab_entries;
116    struct nlist* stab = (struct nlist*)stabC;
117    UChar *next_stabstr = NULL;
118    /* state for various things */
119    struct {
120       Addr     start;         /* start address */
121       Addr     end;           /* end address */
122       Int      line;          /* first line */
123    } func = { 0, 0, -1 };
124    struct {
125       Char     *name;
126       Bool     same;
127    } file = { NULL, True };
128    struct {
129       Int      prev;          /* prev line */
130       Int      no;            /* current line */
131       Int      ovf;           /* line wrap */
132       Addr     addr;          /* start of this line */
133       Bool     first;         /* first line in function */
134    } line = { 0, 0, 0, 0, False };
135
136    /* Ok.  It all looks plausible.  Go on and read debug data. 
137          stab kinds: 100   N_SO     a source file name
138                       68   N_SLINE  a source line number
139                       36   N_FUN    start of a function
140
141       In this loop, we maintain a current file name, updated as 
142       N_SO/N_SOLs appear, and a current function base address, 
143       updated as N_FUNs appear.  Based on that, address ranges for 
144       N_SLINEs are calculated, and stuffed into the line info table.
145
146       Finding the instruction address range covered by an N_SLINE is
147       complicated;  see the N_SLINE case below.
148    */
149    file.name     = ML_(addStr)(di,"???", -1);
150
151    n_stab_entries = stab_sz/(int)sizeof(struct nlist);
152
153    for (i = 0; i < n_stab_entries; i++) {
154       const struct nlist *st = &stab[i];
155       Char *string;
156
157       if (di->trace_symtab) {
158          VG_(printf) ( "%2d  type=%d   othr=%d   desc=%d   "
159                        "value=0x%x   strx=%d  %s\n", i,
160                        st->n_type, st->n_other, st->n_desc, 
161                        (Int)st->n_value,
162                        (Int)st->n_un.n_strx, 
163                        stabstr + st->n_un.n_strx );
164       }
165
166       /* handle continued string stabs */
167       {
168          Int   qbuflen = 0;
169          Int   qidx = 0;
170          Char* qbuf = NULL;
171          Int   qlen;
172          Bool  qcontinuing = False;
173          UInt  qstringidx;
174
175          qstringidx = st->n_un.n_strx;
176          string = stabstr + qstringidx;
177          qlen = VG_(strlen)(string);
178
179          while (string 
180                 && qlen > 0 
181                 && (qcontinuing || string[qlen-1] == '\\')) {
182             /* Gak, we have a continuation. Skip forward through
183                subsequent stabs to gather all the parts of the
184                continuation.  Increment i, but keep st pointing at
185                current stab. */
186
187             qcontinuing = string[qlen-1] == '\\';
188
189             /* remove trailing \ */
190             while (string[qlen-1] == '\\' && qlen > 0)
191                qlen--;
192
193             if (contdebug)
194                VG_(printf)("found extension string: \"%s\" "
195                            "len=%d(%c) idx=%d buflen=%d\n", 
196                            string, qlen, string[qlen-1], qidx, qbuflen);
197
198             /* XXX this is silly.  The si->strtab should have a way of
199                appending to the last added string... */
200             if ((qidx + qlen) >= qbuflen) {
201                Char *n;
202                
203                if (qbuflen == 0)
204                   qbuflen = 16;
205                while ((qidx + qlen) >= qbuflen)
206                   qbuflen *= 2;
207                n = ML_(dinfo_zalloc)("di.readstabs.rds.1", qbuflen);
208                VG_(memcpy)(n, qbuf, qidx);
209                
210                if (qbuf != NULL)
211                   ML_(dinfo_free)(qbuf);
212                qbuf = n;
213             }
214
215             VG_(memcpy)(&qbuf[qidx], string, qlen);
216             qidx += qlen;
217             if (contdebug) {
218                qbuf[qidx] = '\0';
219                VG_(printf)("working buf=\"%s\"\n", qbuf);
220             }
221
222             i++;
223             if (i >= n_stab_entries)
224                break;
225
226             if (stab[i].n_un.n_strx) {
227                string = stabstr + stab[i].n_un.n_strx;
228                qlen = VG_(strlen)(string);
229             } else {
230                string = NULL;
231                qlen = 0;
232             }
233          }
234
235          if (qbuf != NULL) {
236             i--;                        /* overstepped */
237             string = ML_(addStr)(di, qbuf, qidx);
238             ML_(dinfo_free)(qbuf);
239             if (contdebug)
240                VG_(printf)("made composite: \"%s\"\n", string);
241          }
242       }
243
244       switch(st->n_type) {
245          case N_UNDEF:
246             /* new string table base */
247             if (next_stabstr != NULL) {
248                stabstr_sz -= next_stabstr - stabstr;
249                stabstr = next_stabstr;
250                if (stabstr_sz <= 0) {
251                   VG_(printf)(" @@ bad stabstr size %d\n", stabstr_sz);
252                   return;
253                }
254             }
255             next_stabstr = stabstr + st->n_value;
256             break;
257
258          case N_BINCL: {
259             break;
260          }
261
262          case N_EINCL:
263             break;
264
265          case N_EXCL:
266             break;
267
268          case N_SOL:                /* sub-source (include) file */
269             if (line.ovf != 0) 
270                VG_(message)(Vg_UserMsg, 
271                             "Warning: file %s is very big (> 65535 lines) "
272                             "Line numbers and annotation for this file might "
273                             "be wrong.  Sorry.\n",
274                             file.name);
275             /* FALLTHROUGH */
276
277          case N_SO: {                /* new source file */
278             UChar *nm = string;
279             UInt len = VG_(strlen)(nm);
280             Addr addr = func.start + st->n_value;
281
282             if (line.addr != 0) {
283                /* finish off previous line */
284                ML_(addLineInfo)(di, file.name, NULL, line.addr,
285                                 addr, line.no + line.ovf * LINENO_OVERFLOW, i);
286             }
287
288             /* reset line state */
289             line.ovf = 0;            
290             line.addr = 0;
291             line.prev = 0;
292             line.no = 0;
293
294             if (len > 0 && nm[len-1] != '/') {
295                file.name = ML_(addStr)(di, nm, -1);
296                if (debug)
297                   VG_(printf)("new source: %s\n", file.name);
298             } else if (len == 0)
299                file.name = ML_(addStr)(di, "?1\0", -1);
300
301             break;
302          }
303
304          case N_SLINE: {        /* line info */
305             Addr addr = func.start + st->n_value;
306
307             if (line.addr != 0) {
308                /* there was a previous */
309                ML_(addLineInfo)(di, file.name, NULL, line.addr,
310                                 addr, line.no + line.ovf * LINENO_OVERFLOW, i);
311             }
312
313             line.addr = addr;
314             line.prev = line.no;
315             line.no = (Int)((UShort)st->n_desc);
316
317             if (line.prev > line.no + OVERFLOW_DIFFERENCE && file.same) {
318                VG_(message)(Vg_DebugMsg, 
319                   "Line number overflow detected (%d --> %d) in %s\n", 
320                   line.prev, line.no, file.name);
321                line.ovf++;
322             }
323             file.same = True;
324
325             /* This is pretty horrible.  If this is the first line of
326                the function, then bind any unbound symbols to the arg
327                scope, since they're probably arguments. */
328             if (line.first) {
329                line.first = False;
330                
331                /* remember first line of function */
332                if (func.start != 0) {
333                   func.line = line.no;
334                }
335             }
336             break;
337          }
338
339          case N_FUN: {                /* function start/end */
340             Addr addr = 0;        /* end address for prev line/scope */
341
342             /* if this the end of the function or we haven't
343                previously finished the previous function... */
344             if (*string == '\0' || func.start != 0) {
345                /* end of function */
346                line.first = False;
347
348                /* end line at end of function */
349                addr = func.start + st->n_value;
350
351                /* now between functions */
352                func.start = 0;
353
354                // XXXX DEAD POINT XXXX
355             }
356
357             if (*string != '\0') {
358                /* new function */
359                line.first = True;
360
361                /* line ends at start of next function */
362                addr = di->text_debug_bias + st->n_value;
363
364                func.start = addr;
365             }
366
367             if (line.addr) {
368                ML_(addLineInfo)(di, file.name, NULL, line.addr,
369                                 addr, line.no + line.ovf * LINENO_OVERFLOW, i);
370                line.addr = 0;
371             }
372
373             //DEAD POINT
374             //DEAD POINT
375             break;
376          }
377
378          case N_LBRAC: {
379             /* open new scope */
380             // DEAD POINT
381             break;
382          }
383
384          case N_RBRAC: {
385             /* close scope */
386             // DEAD POINT
387             break;
388          }
389
390          case N_GSYM:                /* global variable */
391          case N_STSYM:                /* static in data segment */
392          case N_LCSYM:                /* static in bss segment */
393          case N_PSYM:                /* function parameter */
394          case N_LSYM:                /* stack variable */
395          case N_RSYM:                  /* register variable */
396             break;
397       }
398    }
399 }
400
401 #endif // defined(VGO_linux) || defined(VGO_darwin)
402
403 /*--------------------------------------------------------------------*/
404 /*--- end                                                          ---*/
405 /*--------------------------------------------------------------------*/