ReactOS  0.4.14-dev-317-g96040ec
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 #define NTOSAPI
12 #include <ntddk.h>
13 #include <reactos/rossym.h>
14 #include "rossympriv.h"
15 #include <ntimage.h>
16 
17 #define NDEBUG
18 #include <debug.h>
19 
20 #include "dwarf.h"
21 
22 #define trace 0
23 
24 typedef struct State State;
25 struct State
26 {
31  char *augmentation;
32  int version;
39  int nr;
41  int nstack;
42 };
43 
44 static int findfde(Dwarf*, ulong, State*, DwarfBuf*);
45 static int dexec(DwarfBuf*, State*, int);
46 
47 int
49 {
50  int i, ret;
51  DwarfBuf fde, b;
52  DwarfExpr *initr;
53  State s;
54 
55  initr = mallocz(nr*sizeof(initr[0]), 1);
56  if(initr == 0)
57  return -1;
58 
59  memset(&s, 0, sizeof s);
60  s.loc = 0;
61  s.cfa = cfa;
62  s.ra = ra;
63  s.r = r;
64  s.nr = nr;
65 
66  if(findfde(d, pc, &s, &fde) < 0){
67  free(initr);
68  return -1;
69  }
70 
71  memset(r, 0, nr*sizeof(r[0]));
72  for(i=0; i<nr; i++)
73  r[i].type = RuleSame;
74  if(trace) werrstr("s.init %p-%p, fde %p-%p\n", s.init.p, s.init.ep, fde.p, fde.ep);
75  b = s.init;
76  if(dexec(&b, &s, 0) < 0)
77  goto err;
78 
79  s.initr = initr;
80  memmove(initr, r, nr*sizeof(initr[0]));
81 
82  if(trace) werrstr("s.loc 0x%lux pc 0x%lux\n", s.loc, pc);
83  while(s.loc < pc){
84  if(trace) werrstr("s.loc 0x%lux pc 0x%lux\n", s.loc, pc);
85  if(dexec(&fde, &s, 1) < 0)
86  goto err;
87  }
88  *ra = s.r[s.rareg];
89 
90  ret = 0;
91  goto out;
92 
93 err:
94  ret = -1;
95 out:
96  free(initr);
97  for(i=0; i<s.nstack; i++)
98  free(s.stack[i]);
99  free(s.stack);
100  return ret;
101 }
102 
103 /*
104  * XXX This turns out to be much more expensive than the actual
105  * running of the machine in dexec. It probably makes sense to
106  * cache the last 10 or so fde's we've found, since stack traces
107  * will keep asking for the same info over and over.
108  */
109 static int
111 {
112  static int nbad;
113  char *aug;
114  uchar *next;
115  int i, vers;
116  ulong len, id, base, size;
117  DwarfBuf b;
118 
119  if(d->frame.data == nil){
120  werrstr("no frame debugging information");
121  return -1;
122  }
123  b.d = d;
124  b.p = d->frame.data;
125  b.ep = b.p + d->frame.len;
126  b.addrsize = d->addrsize;
127  if(b.addrsize == 0)
128  b.addrsize = 4; /* where should i find this? */
129 
130  for(; b.p < b.ep; b.p = next){
131  if((i = (b.p - d->frame.data) % b.addrsize))
132  b.p += b.addrsize - i;
133  len = dwarfget4(&b);
134  if(len > b.ep-b.p){
135  werrstr("bad length in cie/fde header");
136  return -1;
137  }
138  next = b.p+len;
139  id = dwarfget4(&b);
140  if(id == 0xFFFFFFFF){ /* CIE */
141  vers = dwarfget1(&b);
142  if(vers != 1 && vers != 2 && vers != 3){
143  if(++nbad == 1)
144  werrstr("unknown cie version %d (wanted 1-3)\n", vers);
145  continue;
146  }
147  aug = dwarfgetstring(&b);
148  if(aug && *aug){
149  if(++nbad == 1)
150  werrstr("unknown augmentation: %s\n", aug);
151  continue;
152  }
153  s->iquantum = dwarfget128(&b);
154  s->dquantum = dwarfget128s(&b);
155  s->rareg = dwarfget128(&b);
156  if(s->rareg > s->nr){
157  werrstr("return address is register %d but only have %d registers",
158  s->rareg, s->nr);
159  return -1;
160  }
161  s->init.p = b.p;
162  s->init.ep = next;
163  }else{ /* FDE */
164  base = dwarfgetaddr(&b);
165  size = dwarfgetaddr(&b);
166  fde->p = b.p;
167  fde->ep = next;
168  s->loc = base;
169  s->endloc = base+size;
170  if(base <= pc && pc < base+size)
171  return 0;
172  }
173  }
174  werrstr("cannot find call frame information for pc 0x%lux", pc);
175  return -1;
176 
177 }
178 
179 static int
180 checkreg(State *s, long r)
181 {
182  if(r < 0 || r >= s->nr){
183  werrstr("bad register number 0x%lux", r);
184  return -1;
185  }
186  return 0;
187 }
188 
189 static int
190 dexec(DwarfBuf *b, State *s, int locstop)
191 {
192  int c;
193  long arg1, arg2;
194  DwarfExpr *e;
195 
196  for(;;){
197  if(b->p == b->ep){
198  if(s->initr)
199  s->loc = s->endloc;
200  return 0;
201  }
202  c = dwarfget1(b);
203  if(b->p == nil){
204  werrstr("ran out of instructions during cfa program");
205  if(trace) werrstr("%r\n");
206  return -1;
207  }
208  if(trace) werrstr("+ loc=0x%lux op 0x%ux ", s->loc, c);
209  switch(c>>6){
210  case 1: /* advance location */
211  arg1 = c&0x3F;
212  advance:
213  if(trace) werrstr("loc += %ld\n", arg1*s->iquantum);
214  s->loc += arg1 * s->iquantum;
215  if(locstop)
216  return 0;
217  continue;
218 
219  case 2: /* offset rule */
220  arg1 = c&0x3F;
221  arg2 = dwarfget128(b);
222  offset:
223  if(trace) werrstr("r%ld += %ld\n", arg1, arg2*s->dquantum);
224  if(checkreg(s, arg1) < 0)
225  return -1;
226  s->r[arg1].type = RuleCfaOffset;
227  s->r[arg1].offset = arg2 * s->dquantum;
228  continue;
229 
230  case 3: /* restore initial setting */
231  arg1 = c&0x3F;
232  restore:
233  if(trace) werrstr("r%ld = init\n", arg1);
234  if(checkreg(s, arg1) < 0)
235  return -1;
236  s->r[arg1] = s->initr[arg1];
237  continue;
238  }
239 
240  switch(c){
241  case 0: /* nop */
242  if(trace) werrstr("nop\n");
243  continue;
244 
245  case 0x01: /* set location */
246  s->loc = dwarfgetaddr(b);
247  if(trace) werrstr("loc = 0x%lux\n", s->loc);
248  if(locstop)
249  return 0;
250  continue;
251 
252  case 0x02: /* advance loc1 */
253  arg1 = dwarfget1(b);
254  goto advance;
255 
256  case 0x03: /* advance loc2 */
257  arg1 = dwarfget2(b);
258  goto advance;
259 
260  case 0x04: /* advance loc4 */
261  arg1 = dwarfget4(b);
262  goto advance;
263 
264  case 0x05: /* offset extended */
265  arg1 = dwarfget128(b);
266  arg2 = dwarfget128(b);
267  goto offset;
268 
269  case 0x06: /* restore extended */
270  arg1 = dwarfget128(b);
271  goto restore;
272 
273  case 0x07: /* undefined */
274  arg1 = dwarfget128(b);
275  if(trace) werrstr("r%ld = undef\n", arg1);
276  if(checkreg(s, arg1) < 0)
277  return -1;
278  s->r[arg1].type = RuleUndef;
279  continue;
280 
281  case 0x08: /* same value */
282  arg1 = dwarfget128(b);
283  if(trace) werrstr("r%ld = same\n", arg1);
284  if(checkreg(s, arg1) < 0)
285  return -1;
286  s->r[arg1].type = RuleSame;
287  continue;
288 
289  case 0x09: /* register */
290  arg1 = dwarfget128(b);
291  arg2 = dwarfget128(b);
292  if(trace) werrstr("r%ld = r%ld\n", arg1, arg2);
293  if(checkreg(s, arg1) < 0 || checkreg(s, arg2) < 0)
294  return -1;
295  s->r[arg1].type = RuleRegister;
296  s->r[arg1].reg = arg2;
297  continue;
298 
299  case 0x0A: /* remember state */
300  e = malloc(s->nr*sizeof(e[0]));
301  if(trace) werrstr("push\n");
302  if(e == nil)
303  return -1;
304  void *newstack = malloc(s->nstack*sizeof(s->stack[0]));
305  RtlMoveMemory(newstack, s->stack, s->nstack*sizeof(s->stack[0]));
306  if (newstack) {
307  free(s->stack);
308  s->stack = newstack;
309  } else {
310  free(e);
311  return -1;
312  }
313  if(b->p == nil){
314  free(e);
315  return -1;
316  }
317  s->stack[s->nstack++] = e;
318  memmove(e, s->r, s->nr*sizeof(e[0]));
319  continue;
320 
321  case 0x0B: /* restore state */
322  if(trace) werrstr("pop\n");
323  if(s->nstack == 0){
324  werrstr("restore state underflow");
325  return -1;
326  }
327  e = s->stack[s->nstack-1];
328  memmove(s->r, e, s->nr*sizeof(e[0]));
329  free(e);
330  s->nstack--;
331  continue;
332 
333  case 0x0C: /* def cfa */
334  arg1 = dwarfget128(b);
335  arg2 = dwarfget128(b);
336  defcfa:
337  if(trace) werrstr("cfa %ld(r%ld)\n", arg2, arg1);
338  if(checkreg(s, arg1) < 0)
339  return -1;
340  s->cfa->type = RuleRegOff;
341  s->cfa->reg = arg1;
342  s->cfa->offset = arg2;
343  continue;
344 
345  case 0x0D: /* def cfa register */
346  arg1 = dwarfget128(b);
347  if(trace) werrstr("cfa reg r%ld\n", arg1);
348  if(s->cfa->type != RuleRegOff){
349  werrstr("change CFA register but CFA not in register+offset form");
350  return -1;
351  }
352  if(checkreg(s, arg1) < 0)
353  return -1;
354  s->cfa->reg = arg1;
355  continue;
356 
357  case 0x0E: /* def cfa offset */
358  arg1 = dwarfget128(b);
359  cfaoffset:
360  if(trace) werrstr("cfa off %ld\n", arg1);
361  if(s->cfa->type != RuleRegOff){
362  werrstr("change CFA offset but CFA not in register+offset form");
363  return -1;
364  }
365  s->cfa->offset = arg1;
366  continue;
367 
368  case 0x0F: /* def cfa expression */
369  if(trace) werrstr("cfa expr\n");
370  s->cfa->type = RuleLocation;
371  s->cfa->loc.len = dwarfget128(b);
372  s->cfa->loc.data = dwarfgetnref(b, s->cfa->loc.len);
373  continue;
374 
375  case 0x10: /* def reg expression */
376  arg1 = dwarfget128(b);
377  if(trace) werrstr("reg expr r%ld\n", arg1);
378  if(checkreg(s, arg1) < 0)
379  return -1;
380  s->r[arg1].type = RuleLocation;
381  s->r[arg1].loc.len = dwarfget128(b);
382  s->r[arg1].loc.data = dwarfgetnref(b, s->r[arg1].loc.len);
383  continue;
384 
385  case 0x11: /* offset extended */
386  arg1 = dwarfget128(b);
387  arg2 = dwarfget128s(b);
388  goto offset;
389 
390  case 0x12: /* cfa sf */
391  arg1 = dwarfget128(b);
392  arg2 = dwarfget128s(b);
393  goto defcfa;
394 
395  case 0x13: /* cfa offset sf */
396  arg1 = dwarfget128s(b);
397  goto cfaoffset;
398 
399  default: /* unknown */
400  werrstr("unknown opcode 0x%ux in cfa program", c);
401  return -1;
402  }
403  }
404  /* not reached */
405 }
406 
407 
#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
#define free
Definition: debug_ros.c:5
#define mallocz(x, y)
Definition: compat.h:36
GLintptr offset
Definition: glext.h:5920
ulong dwarfget4(DwarfBuf *)
Definition: dwarfget.c:96
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
static int dexec(DwarfBuf *, State *, int)
Definition: dwarfcfa.c:190
#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
static int checkreg(State *s, long r)
Definition: dwarfcfa.c:180
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
int version
Definition: dwarfcfa.c:32
#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
GLsizeiptr size
Definition: glext.h:5919
#define d
Definition: ke_i.h:81
DwarfExpr * initr
Definition: dwarfcfa.c:38
const GLubyte * c
Definition: glext.h:8905
static FILE * out
Definition: regtests2xml.c:44
uchar * p
Definition: dwarf.h:210
long dwarfget128s(DwarfBuf *)
Definition: dwarfget.c:198
ulong dwarfget2(DwarfBuf *)
Definition: dwarfget.c:82
int ret
static int findfde(Dwarf *, ulong, State *, DwarfBuf *)
Definition: dwarfcfa.c: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 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
#define trace
Definition: dwarfcfa.c:22
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
#define nil
Definition: compat.h:23
uchar * ep
Definition: dwarf.h:211
uchar * dwarfgetnref(DwarfBuf *, ulong)
Definition: dwarfget.c:41
#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
ulong dwarfgetaddr(DwarfBuf *)
Definition: dwarfget.c:124
ulong dquantum
Definition: dwarfcfa.c:30