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