ReactOS  0.4.15-dev-1177-g6cb3b62
dwarfpc.c
Go to the documentation of this file.
1 /*
2  * Dwarf pc to source line conversion.
3  *
4  * Maybe should do the reverse here, but what should the interface look like?
5  * One possibility is to use the Plan 9 line2addr interface:
6  *
7  * long line2addr(ulong line, ulong basepc)
8  *
9  * which returns the smallest pc > basepc with line number line (ignoring file name).
10  *
11  * The encoding may be small, but it sure isn't simple!
12  */
13 
14 #include <precomp.h>
15 
16 #define NDEBUG
17 #include <debug.h>
18 #define trace 0
19 
20 enum
21 {
22  Isstmt = 1<<0,
24  EndSequence = 1<<2,
25  PrologueEnd = 1<<3,
27 };
28 
29 typedef struct State State;
30 struct State
31 {
32  ulong addr;
33  ulong file;
34  ulong line;
35  ulong column;
36  ulong flags;
37  ulong isa;
38 };
39 
40 int
41 dwarfpctoline(Dwarf *d, DwarfSym *proc, ulong pc, char **file, char **function, ulong *line)
42 {
43  char *cdir;
44  uchar *prog, *opcount, *end, *dirs;
45  ulong off, unit, len, vers, x, start, lastline;
46  int i, first, firstline, op, a, l, quantum, isstmt, linebase, linerange, opcodebase, nf;
47  char *files, *s;
48  DwarfBuf b;
49  DwarfSym sym;
50  State emit, cur, reset;
51  char **f, **newf;
52 
53  f = nil;
54  memset(proc, 0, sizeof(*proc));
55 
56  int runit = dwarfaddrtounit(d, pc, &unit);
57  if (runit < 0)
58  return -1;
59  int rtag = dwarflookuptag(d, unit, TagCompileUnit, &sym);
60  if (rtag < 0)
61  return -1;
62 
63  if(!sym.attrs.have.stmtlist){
64  werrstr("no line mapping information for 0x%x", pc);
65  return -1;
66  }
67  off = sym.attrs.stmtlist;
68  if(off >= d->line.len){
69  werrstr("bad stmtlist");
70  goto bad;
71  }
72 
73  if(trace) werrstr("unit 0x%x stmtlist 0x%x", unit, sym.attrs.stmtlist);
74 
75  memset(&b, 0, sizeof b);
76  b.d = d;
77  b.p = d->line.data + off;
78  b.ep = b.p + d->line.len;
79  b.addrsize = sym.b.addrsize; /* should i get this from somewhere else? */
80 
81  len = dwarfget4(&b);
82  if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
83  werrstr("bad len");
84  goto bad;
85  }
86 
87  b.ep = b.p+len;
88  vers = dwarfget2(&b);
89  if(vers != 2){
90  werrstr("bad dwarf version 0x%x", vers);
91  return -1;
92  }
93 
94  len = dwarfget4(&b);
95  if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
96  werrstr("another bad len");
97  goto bad;
98  }
99  prog = b.p+len;
100 
101  quantum = dwarfget1(&b);
102  isstmt = dwarfget1(&b);
103  linebase = (schar)dwarfget1(&b);
104  linerange = (schar)dwarfget1(&b);
105  opcodebase = dwarfget1(&b);
106 
107  opcount = b.p-1;
108  dwarfgetnref(&b, opcodebase-1);
109  if(b.p == nil){
110  werrstr("bad opcode chart");
111  goto bad;
112  }
113 
114  /* just skip the files and dirs for now; we'll come back */
115  dirs = b.p;
116  while (b.p && *b.p)
117  dwarfgetstring(&b);
118  dwarfget1(&b);
119 
120  files = (char*)b.p;
121  while(b.p!=nil && *b.p!=0){
122  dwarfgetstring(&b);
123  dwarfget128(&b);
124  dwarfget128(&b);
125  dwarfget128(&b);
126  }
127  dwarfget1(&b);
128 
129  /* move on to the program */
130  if(b.p == nil || b.p > prog){
131  werrstr("bad header");
132  goto bad;
133  }
134  b.p = prog;
135 
136  reset.addr = 0;
137  reset.file = 1;
138  reset.line = 1;
139  reset.column = 0;
140  reset.flags = isstmt ? Isstmt : 0;
141  reset.isa = 0;
142 
143  cur = reset;
144  emit = reset;
145  nf = 0;
146  start = 0;
147  if(trace) werrstr("program @ %lu ... %.*H opbase = %d", b.p - d->line.data, b.ep-b.p, b.p, opcodebase);
148  first = 1;
149  while(b.p != nil){
150  firstline = 0;
151  op = dwarfget1(&b);
152  if(trace) werrstr("\tline %lu, addr 0x%x, op %d %.10H", cur.line, cur.addr, op, b.p);
153  if(op >= opcodebase){
154  a = (op - opcodebase) / linerange;
155  l = (op - opcodebase) % linerange + linebase;
156  cur.line += l;
157  cur.addr += a * quantum;
158  if(trace) werrstr(" +%d,%d", a, l);
159  emit:
160  if(first){
161  if(cur.addr > pc){
162  werrstr("found wrong line mapping 0x%x for pc 0x%x", cur.addr, pc);
163  /* This is an overzealous check. gcc can produce discontiguous ranges
164  and reorder statements, so it's possible for a future line to start
165  ahead of pc and still find a matching one. */
166  /*goto out;*/
167  firstline = 1;
168  }
169  first = 0;
170  start = cur.addr;
171  }
172  if(cur.addr > pc && !firstline)
173  break;
174  if(b.p == nil){
175  werrstr("buffer underflow in line mapping");
176  goto out;
177  }
178  emit = cur;
179  if(emit.flags & EndSequence){
180  werrstr("found wrong line mapping 0x%x-0x%x for pc 0x%x", start, cur.addr, pc);
181  goto out;
182  }
184  }else{
185  switch(op){
186  case 0: /* extended op code */
187  if(trace) werrstr(" ext");
188  len = dwarfget128(&b);
189  end = b.p+len;
190  if(b.p == nil || end > b.ep || end < b.p || len < 1)
191  goto bad;
192  switch(dwarfget1(&b)){
193  case 1: /* end sequence */
194  if(trace) werrstr(" end");
195  cur.flags |= EndSequence;
196  goto emit;
197  case 2: /* set address */
198  cur.addr = dwarfgetaddr(&b);
199  if(trace) werrstr(" set pc 0x%x", cur.addr);
200  break;
201  case 3: /* define file */
202  newf = malloc(nf+1*sizeof(f[0]));
203  if (newf)
204  RtlMoveMemory(newf, f, nf*sizeof(f[0]));
205  if(newf == nil)
206  goto out;
207  free(f);
208  f = newf;
209  f[nf++] = s = dwarfgetstring(&b);
210  DPRINT1("str %s", s);
211  dwarfget128(&b);
212  dwarfget128(&b);
213  dwarfget128(&b);
214  if(trace) werrstr(" def file %s", s);
215  break;
216  }
217  if(b.p == nil || b.p > end)
218  goto bad;
219  b.p = end;
220  break;
221  case 1: /* emit */
222  if(trace) werrstr(" emit");
223  goto emit;
224  case 2: /* advance pc */
225  a = dwarfget128(&b);
226  if(trace) werrstr(" advance pc + %lu", a*quantum);
227  cur.addr += a * quantum;
228  break;
229  case 3: /* advance line */
230  l = dwarfget128s(&b);
231  if(trace) werrstr(" advance line + %ld", l);
232  cur.line += l;
233  break;
234  case 4: /* set file */
235  if(trace) werrstr(" set file");
236  cur.file = dwarfget128s(&b);
237  break;
238  case 5: /* set column */
239  if(trace) werrstr(" set column");
240  cur.column = dwarfget128(&b);
241  break;
242  case 6: /* negate stmt */
243  if(trace) werrstr(" negate stmt");
244  cur.flags ^= Isstmt;
245  break;
246  case 7: /* set basic block */
247  if(trace) werrstr(" set basic block");
248  cur.flags |= BasicDwarfBlock;
249  break;
250  case 8: /* const add pc */
251  a = (255 - opcodebase) / linerange * quantum;
252  if(trace) werrstr(" const add pc + %d", a);
253  cur.addr += a;
254  break;
255  case 9: /* fixed advance pc */
256  a = dwarfget2(&b);
257  if(trace) werrstr(" fixed advance pc + %d", a);
258  cur.addr += a;
259  break;
260  case 10: /* set prologue end */
261  if(trace) werrstr(" set prologue end");
262  cur.flags |= PrologueEnd;
263  break;
264  case 11: /* set epilogue begin */
265  if(trace) werrstr(" set epilogue begin");
266  cur.flags |= EpilogueBegin;
267  break;
268  case 12: /* set isa */
269  if(trace) werrstr(" set isa");
270  cur.isa = dwarfget128(&b);
271  break;
272  default: /* something new - skip it */
273  if(trace) werrstr(" unknown %d", opcount[op]);
274  for(i=0; i<opcount[op]; i++)
275  dwarfget128(&b);
276  break;
277  }
278  }
279  }
280  if(b.p == nil)
281  goto bad;
282 
283  /* finally! the data we seek is in "emit" */
284 
285  if(emit.file == 0){
286  werrstr("invalid file index in mapping data");
287  goto out;
288  }
289  if(line)
290  *line = emit.line;
291 
292  /* skip over first emit.file-2 guys */
293  b.p = (uchar*)files;
294  for(i=emit.file-1; i > 0 && b.p!=nil && *b.p!=0; i--){
295  dwarfgetstring(&b);
296  dwarfget128(&b);
297  dwarfget128(&b);
298  dwarfget128(&b);
299  }
300  if(b.p == nil){
301  werrstr("problem parsing file data second time (cannot happen)");
302  goto bad;
303  }
304  if(*b.p == 0){
305  if(i >= nf){
306  werrstr("bad file index in mapping data");
307  goto bad;
308  }
309  b.p = (uchar*)f[i];
310  }
311  s = dwarfgetstring(&b);
312  *file = s;
313  i = dwarfget128(&b); /* directory */
314  x = dwarfget128(&b);
315  x = dwarfget128(&b);
316 
317  /* fetch dir name */
318  cdir = sym.attrs.have.compdir ? sym.attrs.compdir : 0;
319 
320  char *dwarfdir;
321  dwarfdir = nil;
322  b.p = dirs;
323  for (x = 1; b.p && *b.p; x++) {
324  dwarfdir = dwarfgetstring(&b);
325  if (x == i) break;
326  }
327 
328  if (!cdir && dwarfdir)
329  cdir = dwarfdir;
330 
331  char *filefull = malloc(strlen(cdir) + strlen(*file) + 2);
332  strcpy(filefull, cdir);
333  strcat(filefull, "/");
334  strcat(filefull, *file);
335  *file = filefull;
336 
337  *function = nil;
338  lastline = 0;
339 
340  runit = dwarfaddrtounit(d, pc, &unit);
341  if (runit == 0) {
342  DwarfSym compunit = { };
343  int renum = dwarfenumunit(d, unit, &compunit);
344  if (renum < 0)
345  return -1;
346  renum = dwarfnextsymat(d, &compunit, proc);
347  while (renum == 0) {
348  if (proc->attrs.tag == TagSubprogram &&
349  proc->attrs.have.name)
350  {
351  if (proc->attrs.lowpc <= pc && proc->attrs.highpc > pc) {
352  *function = malloc(strlen(proc->attrs.name)+1);
353  strcpy(*function, proc->attrs.name);
354  goto done;
355  }
356  }
357  renum = dwarfnextsym(d, proc);
358  }
359  }
360 
361  // Next search by declaration
362  runit = dwarfaddrtounit(d, pc, &unit);
363  if (runit == 0) {
364  DwarfSym compunit = { };
365  int renum = dwarfenumunit(d, unit, &compunit);
366  if (renum < 0)
367  return -1;
368  renum = dwarfnextsymat(d, &compunit, proc);
369  while (renum == 0) {
370  if (proc->attrs.tag == TagSubprogram &&
371  proc->attrs.have.name &&
372  proc->attrs.declfile == emit.file)
373  {
374  if (proc->attrs.declline <= *line &&
375  proc->attrs.declline > lastline) {
376  free(*function);
377  *function = malloc(strlen(proc->attrs.name)+1);
378  strcpy(*function, proc->attrs.name);
379  goto done;
380  }
381  lastline = proc->attrs.declline;
382  }
383  renum = dwarfnextsym(d, proc);
384  }
385  }
386 
387  /* free at last, free at last */
388 done:
389  free(f);
390  return 0;
391 bad:
392  werrstr("corrupted line mapping for 0x%x", pc);
393 out:
394  free(f);
395  return -1;
396 }
397 
399 {
400  int i;
401  free(LineInfo->FileName);
402  LineInfo->FileName = NULL;
403  free(LineInfo->FunctionName);
404  LineInfo->FunctionName = NULL;
405  for (i = 0; i < sizeof(LineInfo->Parameters)/sizeof(LineInfo->Parameters[0]); i++)
406  free(LineInfo->Parameters[i].ValueName);
407 }
uint addrsize
Definition: dwarf.h:212
int dwarfaddrtounit(Dwarf *, ulong, ulong *)
Definition: dwarfaranges.c:17
#define werrstr(str,...)
Definition: compat.h:34
int dwarfnextsym(Dwarf *, DwarfSym *)
Definition: dwarfinfo.c:251
#define trace
Definition: dwarfpc.c:18
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
unsigned char uchar
Definition: Unfrag.h:59
char * FileName
Definition: rossym.h:86
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * dwarfgetstring(DwarfBuf *)
Definition: dwarfget.c:55
char * prog
Definition: isohybrid.c:47
#define free
Definition: debug_ros.c:5
const GLint * first
Definition: glext.h:5794
ulong dwarfget4(DwarfBuf *)
Definition: dwarfget.c:96
int dwarfnextsymat(Dwarf *, DwarfSym *, int)
Definition: dwarfinfo.c:293
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
signed char schar
Definition: compat.h:5
Definition: dwarfpc.c:30
GLuint GLuint end
Definition: gl.h:1545
static HANDLE proc()
Definition: pdb.c:32
ulong addr
Definition: dwarfpc.c:40
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
int dwarfpctoline(Dwarf *d, ulong pc, char **cdir, char **dir, char **file, char **function, ulong *line, ulong *mtime, ulong *length)
Definition: dwarfpc.c:49
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
ulong dwarfget1(DwarfBuf *)
Definition: dwarfget.c:18
#define a
Definition: ke_i.h:78
ROSSYM_PARAMETER Parameters[16]
Definition: rossym.h:90
struct DwarfAttrs::@4100 have
uchar compdir
Definition: dwarf.h:239
png_const_structrp png_const_inforp int * unit
Definition: png.h:2161
char * ValueName
Definition: rossym.h:67
smooth NULL
Definition: ftsmooth.c:416
Definition: parser.c:48
int dwarfenumunit(Dwarf *, ulong, DwarfSym *)
Definition: dwarfinfo.c:202
#define b
Definition: ke_i.h:79
r l[0]
Definition: byte_order.h:167
GLfloat f
Definition: glext.h:7540
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
#define d
Definition: ke_i.h:81
char * FunctionName
Definition: rossym.h:87
static FILE * out
Definition: regtests2xml.c:44
ulong flags
Definition: dwarfpc.c:44
UINT op
Definition: effect.c:224
ulong column
Definition: dwarfpc.c:43
long dwarfget128s(DwarfBuf *)
Definition: dwarfget.c:198
ulong dwarfget2(DwarfBuf *)
Definition: dwarfget.c:82
uchar stmtlist
Definition: dwarf.h:282
ulong file
Definition: dwarfpc.c:41
ulong line
Definition: dwarfpc.c:42
GLenum GLsizei len
Definition: glext.h:6722
GLdouble s
Definition: gl.h:2039
unsigned long ulong
Definition: linux.h:275
DwarfBuf b
Definition: dwarf.h:378
GLboolean reset
Definition: glext.h:5666
ulong dwarfget128(DwarfBuf *)
Definition: dwarfget.c:153
GLuint start
Definition: gl.h:1545
#define f
Definition: ke_i.h:83
Definition: dwarf.h:436
#define DPRINT1
Definition: precomp.h:8
#define nil
Definition: compat.h:23
ulong isa
Definition: dwarfpc.c:45
uchar * dwarfgetnref(DwarfBuf *, ulong)
Definition: dwarfget.c:41
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define malloc
Definition: debug_ros.c:4
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
int dwarflookuptag(Dwarf *, ulong, ulong, DwarfSym *)
Definition: dwarfinfo.c:152
#define memset(x, y, z)
Definition: compat.h:39
ulong dwarfgetaddr(DwarfBuf *)
Definition: dwarfget.c:124
DwarfAttrs attrs
Definition: dwarf.h:375
off
Definition: i386-dis.c:3909
VOID RosSymFreeInfo(PROSSYM_LINEINFO LineInfo)
Definition: dwarfpc.c:398
Definition: fci.c:126