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