PageRenderTime 87ms CodeModel.GetById 53ms RepoModel.GetById 1ms app.codeStats 0ms

/valgrind-3.7.0/coregrind/m_debuginfo/readstabs.c

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