2 * Dwarf call frame unwinding.
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
18 typedef struct State State
;
38 static int findfde(Dwarf
*, ulong
, State
*, DwarfBuf
*);
39 static int dexec(DwarfBuf
*, State
*, int);
42 dwarfunwind(Dwarf
*d
, ulong pc
, DwarfExpr
*cfa
, DwarfExpr
*ra
, DwarfExpr
*r
, int nr
)
49 initr
= mallocz(nr
*sizeof(initr
[0]), 1);
53 memset(&s
, 0, sizeof s
);
60 if(findfde(d
, pc
, &s
, &fde
) < 0){
65 memset(r
, 0, nr
*sizeof(r
[0]));
68 if(trace
) werrstr("s.init %p-%p, fde %p-%p", s
.init
.p
, s
.init
.ep
, fde
.p
, fde
.ep
);
70 if(dexec(&b
, &s
, 0) < 0)
74 memmove(initr
, r
, nr
*sizeof(initr
[0]));
76 if(trace
) werrstr("s.loc 0x%lx pc 0x%lx", s
.loc
, pc
);
78 if(trace
) werrstr("s.loc 0x%lx pc 0x%lx", s
.loc
, pc
);
79 if(dexec(&fde
, &s
, 1) < 0)
91 for(i
=0; i
<s
.nstack
; i
++)
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.
104 findfde(Dwarf
*d
, ulong pc
, State
*s
, DwarfBuf
*fde
)
110 ulong len
, id
, base
, size
;
113 if(d
->frame
.data
== nil
){
114 werrstr("no frame debugging information");
119 b
.ep
= b
.p
+ d
->frame
.len
;
120 b
.addrsize
= d
->addrsize
;
122 b
.addrsize
= 4; /* where should i find this? */
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
;
129 werrstr("bad length in cie/fde header");
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){
139 werrstr("unknown cie version %d (wanted 1-3)", vers
);
142 aug
= dwarfgetstring(&b
);
145 werrstr("unknown augmentation: %s", aug
);
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",
159 base
= dwarfgetaddr(&b
);
160 size
= dwarfgetaddr(&b
);
161 if (trace
) werrstr("FDE: base %x-%x (want pc %x)", base
, base
+size
, pc
);
165 s
->endloc
= base
+size
;
166 if(base
<= pc
&& pc
< base
+size
)
170 werrstr("cannot find call frame information for pc 0x%lx", pc
);
176 checkreg(State
*s
, long r
)
178 if(r
< 0 || r
>= s
->nr
){
179 werrstr("bad register number 0x%lx", r
);
186 dexec(DwarfBuf
*b
, State
*s
, int locstop
)
196 werrstr("end dexec");
201 werrstr("ran out of instructions during cfa program");
202 if(trace
) werrstr("%r");
205 if(trace
) werrstr("+ loc=0x%x op 0x%x ", s
->loc
, c
);
207 case 1: /* advance location */
210 if(trace
) werrstr("loc += %ld", arg1
*s
->iquantum
);
211 s
->loc
+= arg1
* s
->iquantum
;
216 case 2: /* offset rule */
218 arg2
= dwarfget128(b
);
220 if(trace
) werrstr("r%ld += %ld", arg1
, arg2
*s
->dquantum
);
221 if(checkreg(s
, arg1
) < 0)
223 s
->r
[arg1
].type
= RuleCfaOffset
;
224 s
->r
[arg1
].offset
= arg2
* s
->dquantum
;
227 case 3: /* restore initial setting */
230 if(trace
) werrstr("r%ld = init", arg1
);
231 if(checkreg(s
, arg1
) < 0)
233 s
->r
[arg1
] = s
->initr
[arg1
];
239 if(trace
) werrstr("nop");
242 case 0x01: /* set location */
243 s
->loc
= dwarfgetaddr(b
);
244 if(trace
) werrstr("loc = 0x%lx", s
->loc
);
249 case 0x02: /* advance loc1 */
253 case 0x03: /* advance loc2 */
257 case 0x04: /* advance loc4 */
261 case 0x05: /* offset extended */
262 arg1
= dwarfget128(b
);
263 arg2
= dwarfget128(b
);
266 case 0x06: /* restore extended */
267 arg1
= dwarfget128(b
);
270 case 0x07: /* undefined */
271 arg1
= dwarfget128(b
);
272 if(trace
) werrstr("r%ld = undef", arg1
);
273 if(checkreg(s
, arg1
) < 0)
275 s
->r
[arg1
].type
= RuleUndef
;
278 case 0x08: /* same value */
279 arg1
= dwarfget128(b
);
280 if(trace
) werrstr("r%ld = same", arg1
);
281 if(checkreg(s
, arg1
) < 0)
283 s
->r
[arg1
].type
= RuleSame
;
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)
292 s
->r
[arg1
].type
= RuleRegister
;
293 s
->r
[arg1
].reg
= arg2
;
296 case 0x0A: /* remember state */
297 e
= malloc(s
->nr
*sizeof(e
[0]));
298 if(trace
) werrstr("push");
301 void *newstack
= malloc(s
->nstack
*sizeof(s
->stack
[0]));
302 RtlMoveMemory(newstack
, s
->stack
, s
->nstack
*sizeof(s
->stack
[0]));
314 s
->stack
[s
->nstack
++] = e
;
315 memmove(e
, s
->r
, s
->nr
*sizeof(e
[0]));
318 case 0x0B: /* restore state */
319 if(trace
) werrstr("pop");
321 werrstr("restore state underflow");
324 e
= s
->stack
[s
->nstack
-1];
325 memmove(s
->r
, e
, s
->nr
*sizeof(e
[0]));
330 case 0x0C: /* def cfa */
331 arg1
= dwarfget128(b
);
332 arg2
= dwarfget128(b
);
334 if(trace
) werrstr("cfa %ld(r%ld)", arg2
, arg1
);
335 if(checkreg(s
, arg1
) < 0)
337 s
->cfa
->type
= RuleRegOff
;
339 s
->cfa
->offset
= arg2
;
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");
349 if(checkreg(s
, arg1
) < 0)
354 case 0x0E: /* def cfa offset */
355 arg1
= dwarfget128(b
);
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");
362 s
->cfa
->offset
= arg1
;
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
);
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)
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
);
382 case 0x11: /* offset extended */
383 arg1
= dwarfget128(b
);
384 arg2
= dwarfget128s(b
);
387 case 0x12: /* cfa sf */
388 arg1
= dwarfget128(b
);
389 arg2
= dwarfget128s(b
);
392 case 0x13: /* cfa offset sf */
393 arg1
= dwarfget128s(b
);
396 default: /* unknown */
397 werrstr("unknown opcode 0x%x in cfa program", c
);
404 int dwarfcomputecfa(Dwarf
*d
, DwarfExpr
*cfa
, PROSSYM_REGISTERS registers
, ulong
*cfaLocation
)
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
);
412 werrstr("cfa->type %x", cfa
->type
);
419 int dwarfregunwind(Dwarf
*d
, ulong pc
, ulong fde
, DwarfExpr
*cfa
, PROSSYM_REGISTERS registers
)
423 DwarfExpr initr
[sizeof(registers
->Registers
) / sizeof(registers
->Registers
[0])] = { };
424 DwarfExpr r
[sizeof(registers
->Registers
) / sizeof(registers
->Registers
[0])] = { };
427 int nr
= s
.nr
= sizeof(registers
->Registers
) / sizeof(registers
->Registers
[0]);
430 for (i
= 0; i
< sizeof(r
) / sizeof(r
[0]); i
++) {
431 r
[i
].type
= RuleRegister
;
432 r
[i
].offset
= registers
->Registers
[i
];
436 int res
= dwarfunwind(d
, pc
, cfa
, &ra
, initr
, sizeof(initr
) / sizeof(initr
[0]));
437 if (res
== -1) return -1;
441 if (dwarfcomputecfa(d
, cfa
, registers
, &cfaLocation
) == -1)
444 for (i
= 0; i
< nr
; i
++) {
447 werrstr("Undefined register slot %d", i
);
453 registers
->Registers
[i
] = registers
->Registers
[r
[i
].reg
];
457 RosSymCallbacks
.MemGetProc
459 ®isters
->Registers
[i
],
460 r
[i
].offset
+ registers
->Registers
[r
[i
].reg
],
462 if (!success
) return -1;
467 RosSymCallbacks
.MemGetProc
469 ®isters
->Registers
[i
],
470 r
[i
].offset
+ cfaLocation
,
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;
476 werrstr("We don't yet support cfa rule %d in slot %d", r
[i
].type
, i
);
483 for (i
= 0; i
< sizeof(cfaSpace
) / sizeof(cfaSpace
[0]); i
++) {
484 RosSymCallbacks
.MemGetProc
485 (d
->pe
->fd
, &cfaSpace
[i
], cfaLocation
+ (i
* 4), d
->addrsize
);
487 werrstr("CFA(%x) [%08x, %08x, %08x, %08x]",
488 cfaLocation
, cfaSpace
[0], cfaSpace
[1], cfaSpace
[2], cfaSpace
[3]);