Home | History | Annotate | Download | only in m_debuginfo
      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 (at) 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 */
    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