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