41970587e3a667f72d8c9dd63f3d83cf61ea24d8
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
13 #include <reactos/rossym.h>
14 #include "rossympriv.h"
24 typedef struct State State
;
44 static int findfde(Dwarf
*, ulong
, State
*, DwarfBuf
*);
45 static int dexec(DwarfBuf
*, State
*, int);
48 dwarfunwind(Dwarf
*d
, ulong pc
, DwarfExpr
*cfa
, DwarfExpr
*ra
, DwarfExpr
*r
, int nr
)
55 initr
= mallocz(nr
*sizeof(initr
[0]), 1);
59 memset(&s
, 0, sizeof s
);
66 if(findfde(d
, pc
, &s
, &fde
) < 0){
71 memset(r
, 0, nr
*sizeof(r
[0]));
74 if(trace
) werrstr("s.init %p-%p, fde %p-%p\n", s
.init
.p
, s
.init
.ep
, fde
.p
, fde
.ep
);
76 if(dexec(&b
, &s
, 0) < 0)
80 memmove(initr
, r
, nr
*sizeof(initr
[0]));
82 if(trace
) werrstr("s.loc 0x%lux pc 0x%lux\n", 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)
97 for(i
=0; i
<s
.nstack
; i
++)
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.
110 findfde(Dwarf
*d
, ulong pc
, State
*s
, DwarfBuf
*fde
)
116 ulong len
, id
, base
, size
;
119 if(d
->frame
.data
== nil
){
120 werrstr("no frame debugging information");
125 b
.ep
= b
.p
+ d
->frame
.len
;
126 b
.addrsize
= d
->addrsize
;
128 b
.addrsize
= 4; /* where should i find this? */
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
;
135 werrstr("bad length in cie/fde header");
140 if(id
== 0xFFFFFFFF){ /* CIE */
141 vers
= dwarfget1(&b
);
142 if(vers
!= 1 && vers
!= 2 && vers
!= 3){
144 werrstr("unknown cie version %d (wanted 1-3)\n", vers
);
147 aug
= dwarfgetstring(&b
);
150 werrstr("unknown augmentation: %s\n", aug
);
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",
164 base
= dwarfgetaddr(&b
);
165 size
= dwarfgetaddr(&b
);
169 s
->endloc
= base
+size
;
170 if(base
<= pc
&& pc
< base
+size
)
174 werrstr("cannot find call frame information for pc 0x%lux", pc
);
180 checkreg(State
*s
, long r
)
182 if(r
< 0 || r
>= s
->nr
){
183 werrstr("bad register number 0x%lux", r
);
190 dexec(DwarfBuf
*b
, State
*s
, int locstop
)
204 werrstr("ran out of instructions during cfa program");
205 if(trace
) werrstr("%r\n");
208 if(trace
) werrstr("+ loc=0x%lux op 0x%ux ", s
->loc
, c
);
210 case 1: /* advance location */
213 if(trace
) werrstr("loc += %ld\n", arg1
*s
->iquantum
);
214 s
->loc
+= arg1
* s
->iquantum
;
219 case 2: /* offset rule */
221 arg2
= dwarfget128(b
);
223 if(trace
) werrstr("r%ld += %ld\n", arg1
, arg2
*s
->dquantum
);
224 if(checkreg(s
, arg1
) < 0)
226 s
->r
[arg1
].type
= RuleCfaOffset
;
227 s
->r
[arg1
].offset
= arg2
* s
->dquantum
;
230 case 3: /* restore initial setting */
233 if(trace
) werrstr("r%ld = init\n", arg1
);
234 if(checkreg(s
, arg1
) < 0)
236 s
->r
[arg1
] = s
->initr
[arg1
];
242 if(trace
) werrstr("nop\n");
245 case 0x01: /* set location */
246 s
->loc
= dwarfgetaddr(b
);
247 if(trace
) werrstr("loc = 0x%lux\n", s
->loc
);
252 case 0x02: /* advance loc1 */
256 case 0x03: /* advance loc2 */
260 case 0x04: /* advance loc4 */
264 case 0x05: /* offset extended */
265 arg1
= dwarfget128(b
);
266 arg2
= dwarfget128(b
);
269 case 0x06: /* restore extended */
270 arg1
= dwarfget128(b
);
273 case 0x07: /* undefined */
274 arg1
= dwarfget128(b
);
275 if(trace
) werrstr("r%ld = undef\n", arg1
);
276 if(checkreg(s
, arg1
) < 0)
278 s
->r
[arg1
].type
= RuleUndef
;
281 case 0x08: /* same value */
282 arg1
= dwarfget128(b
);
283 if(trace
) werrstr("r%ld = same\n", arg1
);
284 if(checkreg(s
, arg1
) < 0)
286 s
->r
[arg1
].type
= RuleSame
;
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)
295 s
->r
[arg1
].type
= RuleRegister
;
296 s
->r
[arg1
].reg
= arg2
;
299 case 0x0A: /* remember state */
300 e
= malloc(s
->nr
*sizeof(e
[0]));
301 if(trace
) werrstr("push\n");
304 void *newstack
= malloc(s
->nstack
*sizeof(s
->stack
[0]));
305 RtlMoveMemory(newstack
, s
->stack
, s
->nstack
*sizeof(s
->stack
[0]));
317 s
->stack
[s
->nstack
++] = e
;
318 memmove(e
, s
->r
, s
->nr
*sizeof(e
[0]));
321 case 0x0B: /* restore state */
322 if(trace
) werrstr("pop\n");
324 werrstr("restore state underflow");
327 e
= s
->stack
[s
->nstack
-1];
328 memmove(s
->r
, e
, s
->nr
*sizeof(e
[0]));
333 case 0x0C: /* def cfa */
334 arg1
= dwarfget128(b
);
335 arg2
= dwarfget128(b
);
337 if(trace
) werrstr("cfa %ld(r%ld)\n", arg2
, arg1
);
338 if(checkreg(s
, arg1
) < 0)
340 s
->cfa
->type
= RuleRegOff
;
342 s
->cfa
->offset
= arg2
;
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");
352 if(checkreg(s
, arg1
) < 0)
357 case 0x0E: /* def cfa offset */
358 arg1
= dwarfget128(b
);
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");
365 s
->cfa
->offset
= arg1
;
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
);
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)
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
);
385 case 0x11: /* offset extended */
386 arg1
= dwarfget128(b
);
387 arg2
= dwarfget128s(b
);
390 case 0x12: /* cfa sf */
391 arg1
= dwarfget128(b
);
392 arg2
= dwarfget128s(b
);
395 case 0x13: /* cfa offset sf */
396 arg1
= dwarfget128s(b
);
399 default: /* unknown */
400 werrstr("unknown opcode 0x%ux in cfa program", c
);