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