ReactOS 0.4.15-dev-6675-gcbc63d8
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
24typedef struct State State;
25struct State
26{
39 int nr;
41 int nstack;
42};
43
44static int findfde(Dwarf*, ulong, State*, DwarfBuf*);
45static int dexec(DwarfBuf*, State*, int);
46
47int
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
93err:
94 ret = -1;
95out:
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 */
109static 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
179static int
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
189static int
190dexec(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);
388 goto offset;
389
390 case 0x12: /* cfa sf */
391 arg1 = dwarfget128(b);
393 goto defcfa;
394
395 case 0x13: /* cfa offset sf */
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
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
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 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
#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:110
#define trace
Definition: dwarfcfa.c:22
static int checkreg(State *s, long r)
Definition: dwarfcfa.c:180
int dwarfunwind(Dwarf *d, ulong pc, DwarfExpr *cfa, DwarfExpr *ra, DwarfExpr *r, int nr)
Definition: dwarfcfa.c:48
static int dexec(DwarfBuf *, State *, int)
Definition: dwarfcfa.c:190
#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:153
ulong dwarfget2(DwarfBuf *)
Definition: dwarfget.c:82
@ 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
char * dwarfgetstring(DwarfBuf *)
Definition: dwarfget.c:55
ulong dwarfget1(DwarfBuf *)
Definition: dwarfget.c:18
long dwarfget128s(DwarfBuf *)
Definition: dwarfget.c:198
ulong dwarfgetaddr(DwarfBuf *)
Definition: dwarfget.c:124
uchar * dwarfgetnref(DwarfBuf *, ulong)
Definition: dwarfget.c:41
ulong dwarfget4(DwarfBuf *)
Definition: dwarfget.c:96
uchar * p
Definition: dwarf.h:210
uchar * ep
Definition: dwarf.h:211
Definition: dwarf.h:437
char * augmentation
Definition: dwarfcfa.c:31
int nstack
Definition: dwarfcfa.c:41
DwarfExpr * r
Definition: dwarfcfa.c:37
int nr
Definition: dwarfcfa.c:39
ulong loc
Definition: dwarfcfa.c:27
ulong dquantum
Definition: dwarfcfa.c:30
DwarfBuf init
Definition: dwarfcfa.c:34
DwarfExpr * ra
Definition: dwarfcfa.c:36
ulong endloc
Definition: dwarfcfa.c:28
ulong iquantum
Definition: dwarfcfa.c:29
ulong rareg
Definition: dwarfcfa.c:33
DwarfExpr ** stack
Definition: dwarfcfa.c:40
DwarfExpr * initr
Definition: dwarfcfa.c:38
int version
Definition: dwarfcfa.c:32
DwarfExpr * cfa
Definition: dwarfcfa.c:35
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
int ret