ReactOS  0.4.14-dev-342-gdc047f9
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
#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
GLuint GLuint end
Definition: gl.h:1545
static HANDLE proc()
Definition: pdb.c:32
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
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
uchar compdir
Definition: dwarf.h:239
png_const_structrp png_const_inforp int * unit
Definition: png.h:2161
smooth NULL
Definition: ftsmooth.c:416
Definition: parser.c:48
unsigned int dir
Definition: maze.c:112
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
Definition: dwarfpc.c:30
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
static FILE * out
Definition: regtests2xml.c:44
char * name
Definition: compiler.c:66
ulong flags
Definition: dwarfpc.c:44
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 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
struct DwarfAttrs::@3988 have
#define malloc
Definition: debug_ros.c:4
int dwarflookupfn(Dwarf *, ulong, ulong, DwarfSym *)
Definition: dwarfinfo.c:182
UINT op
Definition: effect.c:223
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
Definition: fci.c:126