ReactOS  0.4.14-dev-342-gdc047f9
dwarfcfa.c
Go to the documentation of this file.
1 /*
2  * Dwarf call frame unwinding.
3  *
4  * The call frame unwinding values are encoded using a state machine
5  * like the pc<->line mapping, but it's a different machine.
6  * The expressions to generate the old values are similar in function to the
7  * ``dwarf expressions'' used for locations in the code, but of course not
8  * the same encoding.
9  */
10 
11 #include <precomp.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 #define trace 1
17 
18 typedef struct State State;
19 struct State
20 {
21  ulong loc;
22  ulong endloc;
25  char *augmentation;
26  int version;
27  ulong rareg;
28  DwarfBuf init;
29  DwarfExpr *cfa;
30  DwarfExpr *ra;
31  DwarfExpr *r;
33  int nr;
34  DwarfExpr **stack;
35  int nstack;
36 };
37 
38 static int findfde(Dwarf*, ulong, State*, DwarfBuf*);
39 static int dexec(DwarfBuf*, State*, int);
40 
41 int
43 {
44  int i, ret;
45  DwarfBuf fde, b;
46  DwarfExpr *initr;
47  State s;
48 
49  initr = mallocz(nr*sizeof(initr[0]), 1);
50  if(initr == 0)
51  return -1;
52 
53  memset(&s, 0, sizeof s);
54  s.loc = 0;
55  s.cfa = cfa;
56  s.ra = ra;
57  s.r = r;
58  s.nr = nr;
59 
60  if(findfde(d, pc, &s, &fde) < 0){
61  free(initr);
62  return -1;
63  }
64 
65  memset(r, 0, nr*sizeof(r[0]));
66  for(i=0; i<nr; i++)
67  r[i].type = RuleSame;
68  if(trace) werrstr("s.init %p-%p, fde %p-%p", s.init.p, s.init.ep, fde.p, fde.ep);
69  b = s.init;
70  if(dexec(&b, &s, 0) < 0)
71  goto err;
72 
73  s.initr = initr;
74  memmove(initr, r, nr*sizeof(initr[0]));
75 
76  if(trace) werrstr("s.loc 0x%lx pc 0x%lx", s.loc, pc);
77  while(s.loc < pc){
78  if(trace) werrstr("s.loc 0x%lx pc 0x%lx", s.loc, pc);
79  if(dexec(&fde, &s, 1) < 0)
80  goto err;
81  }
82  *ra = s.r[s.rareg];
83 
84  ret = 0;
85  goto out;
86 
87 err:
88  ret = -1;
89 out:
90  free(initr);
91  for(i=0; i<s.nstack; i++)
92  free(s.stack[i]);
93  free(s.stack);
94  return ret;
95 }
96 
97 /*
98  * XXX This turns out to be much more expensive than the actual
99  * running of the machine in dexec. It probably makes sense to
100  * cache the last 10 or so fde's we've found, since stack traces
101  * will keep asking for the same info over and over.
102  */
103 static int
105 {
106  static int nbad;
107  char *aug;
108  uchar *next;
109  int i, vers;
110  ulong len, id, base, size;
111  DwarfBuf b;
112 
113  if(d->frame.data == nil){
114  werrstr("no frame debugging information");
115  return -1;
116  }
117  b.d = d;
118  b.p = d->frame.data;
119  b.ep = b.p + d->frame.len;
120  b.addrsize = d->addrsize;
121  if(b.addrsize == 0)
122  b.addrsize = 4; /* where should i find this? */
123 
124  for(; b.p < b.ep; b.p = next){
125  if((i = (b.p - d->frame.data) % b.addrsize))
126  b.p += b.addrsize - i;
127  len = dwarfget4(&b);
128  if(len > b.ep-b.p){
129  werrstr("bad length in cie/fde header");
130  return -1;
131  }
132  next = b.p+len;
133  id = dwarfget4(&b);
134  if(id == 0xFFFFFFFF){ /* CIE */
135  vers = dwarfget1(&b);
136  if (trace) werrstr("CIE len %x id %x vers %x", len, id, vers);
137  if(vers != 1 && vers != 2 && vers != 3){
138  if(++nbad == 1)
139  werrstr("unknown cie version %d (wanted 1-3)", vers);
140  continue;
141  }
142  aug = dwarfgetstring(&b);
143  if(aug && *aug){
144  if(++nbad == 1)
145  werrstr("unknown augmentation: %s", aug);
146  continue;
147  }
148  s->iquantum = dwarfget128(&b);
149  s->dquantum = dwarfget128s(&b);
150  s->rareg = dwarfget128(&b);
151  if(s->rareg > s->nr){
152  werrstr("return address is register %d but only have %d registers",
153  s->rareg, s->nr);
154  return -1;
155  }
156  s->init.p = b.p;
157  s->init.ep = next;
158  }else{ /* FDE */
159  base = dwarfgetaddr(&b);
160  size = dwarfgetaddr(&b);
161  if (trace) werrstr("FDE: base %x-%x (want pc %x)", base, base+size, pc);
162  fde->p = b.p;
163  fde->ep = next;
164  s->loc = base;
165  s->endloc = base+size;
166  if(base <= pc && pc < base+size)
167  return 0;
168  }
169  }
170  werrstr("cannot find call frame information for pc 0x%lx", pc);
171  return -1;
172 
173 }
174 
175 static int
176 checkreg(State *s, long r)
177 {
178  if(r < 0 || r >= s->nr){
179  werrstr("bad register number 0x%lx", r);
180  return -1;
181  }
182  return 0;
183 }
184 
185 static int
186 dexec(DwarfBuf *b, State *s, int locstop)
187 {
188  int c;
189  long arg1, arg2;
190  DwarfExpr *e;
191 
192  for(;;){
193  if(b->p == b->ep){
194  if(s->initr)
195  s->loc = s->endloc;
196  werrstr("end dexec");
197  return 0;
198  }
199  c = dwarfget1(b);
200  if(b->p == nil){
201  werrstr("ran out of instructions during cfa program");
202  if(trace) werrstr("%r");
203  return -1;
204  }
205  if(trace) werrstr("+ loc=0x%x op 0x%x ", s->loc, c);
206  switch(c>>6){
207  case 1: /* advance location */
208  arg1 = c&0x3F;
209  advance:
210  if(trace) werrstr("loc += %ld", arg1*s->iquantum);
211  s->loc += arg1 * s->iquantum;
212  if(locstop)
213  return 0;
214  continue;
215 
216  case 2: /* offset rule */
217  arg1 = c&0x3F;
218  arg2 = dwarfget128(b);
219  offset:
220  if(trace) werrstr("r%ld += %ld", arg1, arg2*s->dquantum);
221  if(checkreg(s, arg1) < 0)
222  return -1;
223  s->r[arg1].type = RuleCfaOffset;
224  s->r[arg1].offset = arg2 * s->dquantum;
225  continue;
226 
227  case 3: /* restore initial setting */
228  arg1 = c&0x3F;
229  restore:
230  if(trace) werrstr("r%ld = init", arg1);
231  if(checkreg(s, arg1) < 0)
232  return -1;
233  s->r[arg1] = s->initr[arg1];
234  continue;
235  }
236 
237  switch(c){
238  case 0: /* nop */
239  if(trace) werrstr("nop");
240  continue;
241 
242  case 0x01: /* set location */
243  s->loc = dwarfgetaddr(b);
244  if(trace) werrstr("loc = 0x%lx", s->loc);
245  if(locstop)
246  return 0;
247  continue;
248 
249  case 0x02: /* advance loc1 */
250  arg1 = dwarfget1(b);
251  goto advance;
252 
253  case 0x03: /* advance loc2 */
254  arg1 = dwarfget2(b);
255  goto advance;
256 
257  case 0x04: /* advance loc4 */
258  arg1 = dwarfget4(b);
259  goto advance;
260 
261  case 0x05: /* offset extended */
262  arg1 = dwarfget128(b);
263  arg2 = dwarfget128(b);
264  goto offset;
265 
266  case 0x06: /* restore extended */
267  arg1 = dwarfget128(b);
268  goto restore;
269 
270  case 0x07: /* undefined */
271  arg1 = dwarfget128(b);
272  if(trace) werrstr("r%ld = undef", arg1);
273  if(checkreg(s, arg1) < 0)
274  return -1;
275  s->r[arg1].type = RuleUndef;
276  continue;
277 
278  case 0x08: /* same value */
279  arg1 = dwarfget128(b);
280  if(trace) werrstr("r%ld = same", arg1);
281  if(checkreg(s, arg1) < 0)
282  return -1;
283  s->r[arg1].type = RuleSame;
284  continue;
285 
286  case 0x09: /* register */
287  arg1 = dwarfget128(b);
288  arg2 = dwarfget128(b);
289  if(trace) werrstr("r%ld = r%ld", arg1, arg2);
290  if(checkreg(s, arg1) < 0 || checkreg(s, arg2) < 0)
291  return -1;
292  s->r[arg1].type = RuleRegister;
293  s->r[arg1].reg = arg2;
294  continue;
295 
296  case 0x0A: /* remember state */
297  e = malloc(s->nr*sizeof(e[0]));
298  if(trace) werrstr("push");
299  if(e == nil)
300  return -1;
301  void *newstack = malloc(s->nstack*sizeof(s->stack[0]));
302  RtlMoveMemory(newstack, s->stack, s->nstack*sizeof(s->stack[0]));
303  if (newstack) {
304  free(s->stack);
305  s->stack = newstack;
306  } else {
307  free(e);
308  return -1;
309  }
310  if(b->p == nil){
311  free(e);
312  return -1;
313  }
314  s->stack[s->nstack++] = e;
315  memmove(e, s->r, s->nr*sizeof(e[0]));
316  continue;
317 
318  case 0x0B: /* restore state */
319  if(trace) werrstr("pop");
320  if(s->nstack == 0){
321  werrstr("restore state underflow");
322  return -1;
323  }
324  e = s->stack[s->nstack-1];
325  memmove(s->r, e, s->nr*sizeof(e[0]));
326  free(e);
327  s->nstack--;
328  continue;
329 
330  case 0x0C: /* def cfa */
331  arg1 = dwarfget128(b);
332  arg2 = dwarfget128(b);
333  defcfa:
334  if(trace) werrstr("cfa %ld(r%ld)", arg2, arg1);
335  if(checkreg(s, arg1) < 0)
336  return -1;
337  s->cfa->type = RuleRegOff;
338  s->cfa->reg = arg1;
339  s->cfa->offset = arg2;
340  continue;
341 
342  case 0x0D: /* def cfa register */
343  arg1 = dwarfget128(b);
344  if(trace) werrstr("cfa reg r%ld", arg1);
345  if(s->cfa->type != RuleRegOff){
346  werrstr("change CFA register but CFA not in register+offset form");
347  return -1;
348  }
349  if(checkreg(s, arg1) < 0)
350  return -1;
351  s->cfa->reg = arg1;
352  continue;
353 
354  case 0x0E: /* def cfa offset */
355  arg1 = dwarfget128(b);
356  cfaoffset:
357  if(trace) werrstr("cfa off %ld", arg1);
358  if(s->cfa->type != RuleRegOff){
359  werrstr("change CFA offset but CFA not in register+offset form");
360  return -1;
361  }
362  s->cfa->offset = arg1;
363  continue;
364 
365  case 0x0F: /* def cfa expression */
366  if(trace) werrstr("cfa expr");
367  s->cfa->type = RuleLocation;
368  s->cfa->loc.len = dwarfget128(b);
369  s->cfa->loc.data = dwarfgetnref(b, s->cfa->loc.len);
370  continue;
371 
372  case 0x10: /* def reg expression */
373  arg1 = dwarfget128(b);
374  if(trace) werrstr("reg expr r%ld", arg1);
375  if(checkreg(s, arg1) < 0)
376  return -1;
377  s->r[arg1].type = RuleLocation;
378  s->r[arg1].loc.len = dwarfget128(b);
379  s->r[arg1].loc.data = dwarfgetnref(b, s->r[arg1].loc.len);
380  continue;
381 
382  case 0x11: /* offset extended */
383  arg1 = dwarfget128(b);
384  arg2 = dwarfget128s(b);
385  goto offset;
386 
387  case 0x12: /* cfa sf */
388  arg1 = dwarfget128(b);
389  arg2 = dwarfget128s(b);
390  goto defcfa;
391 
392  case 0x13: /* cfa offset sf */
393  arg1 = dwarfget128s(b);
394  goto cfaoffset;
395 
396  default: /* unknown */
397  werrstr("unknown opcode 0x%x in cfa program", c);
398  return -1;
399  }
400  }
401  /* not reached */
402 }
403 
405 {
406  switch (cfa->type) {
407  case RuleRegOff:
408  *cfaLocation = registers->Registers[cfa->reg] + cfa->offset;
409  werrstr("cfa reg %d (%x) offset %x = %x", cfa->reg, (ulong)registers->Registers[cfa->reg], cfa->offset, cfaLocation);
410  break;
411  default:
412  werrstr("cfa->type %x", cfa->type);
413  return -1;
414  }
415 
416  return 0;
417 }
418 
420 {
421  int i;
422  State s = { };
423  DwarfExpr initr[sizeof(registers->Registers) / sizeof(registers->Registers[0])] = { };
424  DwarfExpr r[sizeof(registers->Registers) / sizeof(registers->Registers[0])] = { };
425  DwarfExpr ra;
426 
427  int nr = s.nr = sizeof(registers->Registers) / sizeof(registers->Registers[0]);
428  s.initr = initr;
429  s.r = r;
430  for (i = 0; i < sizeof(r) / sizeof(r[0]); i++) {
431  r[i].type = RuleRegister;
432  r[i].offset = registers->Registers[i];
433  r[i].reg = i;
434  }
435 
436  int res = dwarfunwind(d, pc, cfa, &ra, initr, sizeof(initr) / sizeof(initr[0]));
437  if (res == -1) return -1;
438 
439  ulong cfaLocation;
440 
441  if (dwarfcomputecfa(d, cfa, registers, &cfaLocation) == -1)
442  return -1;
443 
444  for (i = 0; i < nr; i++) {
445  switch (r[i].type) {
446  case RuleUndef:
447  werrstr("Undefined register slot %d", i);
448  assert(FALSE);
449  break;
450  case RuleSame:
451  break;
452  case RuleRegister:
453  registers->Registers[i] = registers->Registers[r[i].reg];
454  break;
455  case RuleRegOff: {
456  BOOLEAN success =
458  (d->pe->fd,
459  &registers->Registers[i],
460  r[i].offset + registers->Registers[r[i].reg],
461  d->addrsize);
462  if (!success) return -1;
463  } break;
464  case RuleCfaOffset:
465  {
466  BOOLEAN success =
468  (d->pe->fd,
469  &registers->Registers[i],
470  r[i].offset + cfaLocation,
471  d->addrsize);
472  werrstr("reg[%d] = %x: cfa offset (cfa %x, offset %x) -> @%x", i, (ulong)registers->Registers[i], cfaLocation, initr[i].offset, r[i].offset + cfaLocation);
473  if (!success) return -1;
474  } break;
475  default:
476  werrstr("We don't yet support cfa rule %d in slot %d", r[i].type, i);
477  assert(FALSE);
478  break;
479  }
480  }
481 
482  ulong cfaSpace[4];
483  for (i = 0; i < sizeof(cfaSpace) / sizeof(cfaSpace[0]); i++) {
485  (d->pe->fd, &cfaSpace[i], cfaLocation + (i * 4), d->addrsize);
486  }
487  werrstr("CFA(%x) [%08x, %08x, %08x, %08x]",
488  cfaLocation, cfaSpace[0], cfaSpace[1], cfaSpace[2], cfaSpace[3]);
489 
490  return 0;
491 }
#define werrstr(str,...)
Definition: compat.h:34
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
unsigned char uchar
Definition: Unfrag.h:59
ULONG nr
Definition: thread.c:7
int nr
Definition: dwarfcfa.c:39
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
char * dwarfgetstring(DwarfBuf *)
Definition: dwarfget.c:55
int dwarfregunwind(Dwarf *d, ulong pc, ulong fde, DwarfExpr *cfa, PROSSYM_REGISTERS registers)
Definition: dwarfcfa.c:419
#define free
Definition: debug_ros.c:5
#define mallocz(x, y)
Definition: compat.h:36
int dwarfcomputecfa(Dwarf *d, DwarfExpr *cfa, PROSSYM_REGISTERS registers, ulong *cfaLocation)
Definition: dwarfcfa.c:404
GLintptr offset
Definition: glext.h:5920
ulong dwarfget4(DwarfBuf *)
Definition: dwarfget.c:96
static int findfde(Dwarf *, ulong, State *, DwarfBuf *)
Definition: dwarfcfa.c:104
static int dexec(DwarfBuf *, State *, int)
Definition: dwarfcfa.c:186
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define assert(x)
Definition: debug.h:53
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:263
GLuint GLuint GLuint GLuint GLuint GLuint GLuint arg2
Definition: glext.h:9514
ulong endloc
Definition: dwarfcfa.c:28
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
ROSSYM_CALLBACKS RosSymCallbacks
Definition: init.c:14
ulong dwarfget1(DwarfBuf *)
Definition: dwarfget.c:18
DwarfExpr ** stack
Definition: dwarfcfa.c:40
GLuint base
Definition: 3dtext.c:35
#define e
Definition: ke_i.h:82
GLuint GLuint GLuint GLuint arg1
Definition: glext.h:9513
unsigned char BOOLEAN
int version
Definition: dwarfcfa.c:32
long offset
Definition: dwarf.h:368
#define b
Definition: ke_i.h:79
int nstack
Definition: dwarfcfa.c:41
DwarfBuf init
Definition: dwarfcfa.c:34
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
int registers[NUMREGS]
GLsizeiptr size
Definition: glext.h:5919
#define d
Definition: ke_i.h:81
DwarfExpr * initr
Definition: dwarfcfa.c:38
ulong reg
Definition: dwarf.h:369
const GLubyte * c
Definition: glext.h:8905
static FILE * out
Definition: regtests2xml.c:44
#define success(from, fromstr, to, tostr)
uchar * p
Definition: dwarf.h:210
long dwarfget128s(DwarfBuf *)
Definition: dwarfget.c:198
ulong dwarfget2(DwarfBuf *)
Definition: dwarfget.c:82
int ret
BOOLEAN(* MemGetProc)(PVOID FileContext, ULONG_PTR *Target, PVOID SourceMem, ULONG Size)
Definition: rossym.h:110
GLenum GLsizei len
Definition: glext.h:6722
GLdouble s
Definition: gl.h:2039
_STLP_MOVE_TO_STD_NAMESPACE void _STLP_CALL advance(_InputIterator &__i, _Distance __n)
#define trace
Definition: dwarfcfa.c:16
#define err(...)
int dwarfunwind(Dwarf *d, ulong pc, DwarfExpr *cfa, DwarfExpr *ra, DwarfExpr *r, int nr)
Definition: dwarfcfa.c:48
unsigned long ulong
Definition: linux.h:275
static unsigned __int64 next
Definition: rand_nt.c:6
ulong dwarfget128(DwarfBuf *)
Definition: dwarfget.c:153
DwarfExpr * r
Definition: dwarfcfa.c:37
DwarfExpr * ra
Definition: dwarfcfa.c:36
Definition: dwarf.h:436
DwarfExpr * cfa
Definition: dwarfcfa.c:35
ulong loc
Definition: dwarfcfa.c:27
ulong rareg
Definition: dwarfcfa.c:33
static int checkreg(State *s, long r)
Definition: dwarfcfa.c:176
#define nil
Definition: compat.h:23
uchar * ep
Definition: dwarf.h:211
uchar * dwarfgetnref(DwarfBuf *, ulong)
Definition: dwarfget.c:41
GLuint res
Definition: glext.h:9613
#define c
Definition: ke_i.h:80
GLenum GLuint id
Definition: glext.h:5579
#define malloc
Definition: debug_ros.c:4
ulong iquantum
Definition: dwarfcfa.c:29
char * augmentation
Definition: dwarfcfa.c:31
#define memset(x, y, z)
Definition: compat.h:39
int type
Definition: dwarf.h:367
ulong dwarfgetaddr(DwarfBuf *)
Definition: dwarfget.c:124
ulong dquantum
Definition: dwarfcfa.c:30