ReactOS 0.4.15-dev-7842-g558ab78
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
18typedef struct State State;
19struct State
20{
21 ulong loc;
25 char *augmentation;
26 int version;
31 DwarfExpr *r;
33 int nr;
35 int nstack;
36};
37
38static int findfde(Dwarf*, ulong, State*, DwarfBuf*);
39static int dexec(DwarfBuf*, State*, int);
40
41int
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
87err:
88 ret = -1;
89out:
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 */
103static 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
175static int
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
185static int
186dexec(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);
385 goto offset;
386
387 case 0x12: /* cfa sf */
388 arg1 = dwarfget128(b);
390 goto defcfa;
391
392 case 0x13: /* cfa offset sf */
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: {
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 {
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}
unsigned char BOOLEAN
unsigned char uchar
Definition: Unfrag.h:59
_STLP_MOVE_TO_STD_NAMESPACE void _STLP_CALL advance(_InputIterator &__i, _Distance __n)
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define FALSE
Definition: types.h:117
#define assert(x)
Definition: debug.h:53
unsigned long ulong
Definition: linux.h:275
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLsizeiptr size
Definition: glext.h:5919
GLuint res
Definition: glext.h:9613
GLuint GLuint GLuint GLuint arg1
Definition: glext.h:9513
const GLubyte * c
Definition: glext.h:8905
GLuint GLuint GLuint GLuint GLuint GLuint GLuint arg2
Definition: glext.h:9514
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLenum GLsizei len
Definition: glext.h:6722
GLuint id
Definition: glext.h:5910
GLintptr offset
Definition: glext.h:5920
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
int registers[NUMREGS]
#define d
Definition: ke_i.h:81
#define e
Definition: ke_i.h:82
#define c
Definition: ke_i.h:80
#define b
Definition: ke_i.h:79
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
ULONG nr
Definition: thread.c:7
static unsigned __int64 next
Definition: rand_nt.c:6
#define err(...)
static FILE * out
Definition: regtests2xml.c:44
static int findfde(Dwarf *, ulong, State *, DwarfBuf *)
Definition: dwarfcfa.c:109
#define trace
Definition: dwarfcfa.c:21
static int checkreg(State *s, long r)
Definition: dwarfcfa.c:179
int dwarfunwind(Dwarf *d, ulong pc, DwarfExpr *cfa, DwarfExpr *ra, DwarfExpr *r, int nr)
Definition: dwarfcfa.c:47
static int dexec(DwarfBuf *, State *, int)
Definition: dwarfcfa.c:189
int dwarfcomputecfa(Dwarf *d, DwarfExpr *cfa, PROSSYM_REGISTERS registers, ulong *cfaLocation)
Definition: dwarfcfa.c:404
int dwarfregunwind(Dwarf *d, ulong pc, ulong fde, DwarfExpr *cfa, PROSSYM_REGISTERS registers)
Definition: dwarfcfa.c:419
#define werrstr(str,...)
Definition: compat.h:34
#define nil
Definition: compat.h:23
#define mallocz(x, y)
Definition: compat.h:36
#define memset(x, y, z)
Definition: compat.h:39
ulong dwarfget128(DwarfBuf *)
Definition: dwarfget.c:152
ulong dwarfget2(DwarfBuf *)
Definition: dwarfget.c:81
char * dwarfgetstring(DwarfBuf *)
Definition: dwarfget.c:54
ulong dwarfget1(DwarfBuf *)
Definition: dwarfget.c:17
long dwarfget128s(DwarfBuf *)
Definition: dwarfget.c:197
ulong dwarfgetaddr(DwarfBuf *)
Definition: dwarfget.c:123
@ RuleLocation
Definition: dwarf.h:363
@ RuleRegOff
Definition: dwarf.h:362
@ RuleRegister
Definition: dwarf.h:361
@ RuleSame
Definition: dwarf.h:359
@ RuleCfaOffset
Definition: dwarf.h:360
@ RuleUndef
Definition: dwarf.h:358
uchar * dwarfgetnref(DwarfBuf *, ulong)
Definition: dwarfget.c:40
ulong dwarfget4(DwarfBuf *)
Definition: dwarfget.c:95
ROSSYM_CALLBACKS RosSymCallbacks
Definition: init.c:14
uchar * p
Definition: dwarf.h:210
uchar * ep
Definition: dwarf.h:211
int type
Definition: dwarf.h:367
ulong reg
Definition: dwarf.h:369
long offset
Definition: dwarf.h:368
Definition: dwarf.h:437
char * augmentation
Definition: dwarfcfa.c:30
int nstack
Definition: dwarfcfa.c:40
DwarfExpr * r
Definition: dwarfcfa.c:36
int nr
Definition: dwarfcfa.c:38
ulong loc
Definition: dwarfcfa.c:26
ulong dquantum
Definition: dwarfcfa.c:29
DwarfBuf init
Definition: dwarfcfa.c:33
DwarfExpr * ra
Definition: dwarfcfa.c:35
ulong endloc
Definition: dwarfcfa.c:27
ulong iquantum
Definition: dwarfcfa.c:28
ulong rareg
Definition: dwarfcfa.c:32
DwarfExpr ** stack
Definition: dwarfcfa.c:39
DwarfExpr * initr
Definition: dwarfcfa.c:37
int version
Definition: dwarfcfa.c:31
DwarfExpr * cfa
Definition: dwarfcfa.c:34
BOOLEAN(* MemGetProc)(PVOID FileContext, ULONG_PTR *Target, PVOID SourceMem, ULONG Size)
Definition: rossym.h:110
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
int ret
#define success(from, fromstr, to, tostr)