2 * Dwarf pc to source line conversion.
4 * Maybe should do the reverse here, but what should the interface look like?
5 * One possibility is to use the Plan 9 line2addr interface:
7 * long line2addr(ulong line, ulong basepc)
9 * which returns the smallest pc > basepc with line number line (ignoring file name).
11 * The encoding may be small, but it sure isn't simple!
16 #include <reactos/rossym.h>
17 #include "rossympriv.h"
31 BasicDwarfBlock
= 1<<1,
37 typedef struct State State
;
49 dwarfpctoline(Dwarf
*d
, ulong pc
, char **cdir
, char **dir
, char **file
, char **function
, ulong
*line
, ulong
*mtime
, ulong
*length
)
51 uchar
*prog
, *opcount
, *end
, *dirs
;
52 ulong off
, unit
, len
, vers
, x
, start
, lastline
;
53 int i
, first
, firstline
, op
, a
, l
, quantum
, isstmt
, linebase
, linerange
, opcodebase
, nf
;
57 State emit
, cur
, reset
;
62 if(dwarfaddrtounit(d
, pc
, &unit
) < 0
63 || dwarflookuptag(d
, unit
, TagCompileUnit
, &sym
) < 0)
66 if(!sym
.attrs
.have
.stmtlist
){
67 werrstr("no line mapping information for 0x%x", pc
);
70 off
= sym
.attrs
.stmtlist
;
71 if(off
>= d
->line
.len
){
72 werrstr("bad stmtlist\n");
76 if(trace
) werrstr("unit 0x%x stmtlist 0x%x", unit
, sym
.attrs
.stmtlist
);
78 memset(&b
, 0, sizeof b
);
80 b
.p
= d
->line
.data
+ off
;
81 b
.ep
= b
.p
+ d
->line
.len
;
82 b
.addrsize
= sym
.b
.addrsize
; /* should i get this from somewhere else? */
85 if(b
.p
==nil
|| b
.p
+len
> b
.ep
|| b
.p
+len
< b
.p
){
93 werrstr("bad dwarf version 0x%x", vers
);
98 if(b
.p
==nil
|| b
.p
+len
> b
.ep
|| b
.p
+len
< b
.p
){
99 werrstr("another bad len\n");
104 quantum
= dwarfget1(&b
);
105 isstmt
= dwarfget1(&b
);
106 linebase
= (schar
)dwarfget1(&b
);
107 linerange
= (schar
)dwarfget1(&b
);
108 opcodebase
= dwarfget1(&b
);
111 dwarfgetnref(&b
, opcodebase
-1);
113 werrstr("bad opcode chart\n");
117 /* just skip the files and dirs for now; we'll come back */
124 while(b
.p
!=nil
&& *b
.p
!=0){
132 /* move on to the program */
133 if(b
.p
== nil
|| b
.p
> prog
){
134 werrstr("bad header\n");
143 reset
.flags
= isstmt
? Isstmt
: 0;
150 if(trace
) werrstr("program @ %lu ... %.*H opbase = %d\n", b
.p
- d
->line
.data
, b
.ep
-b
.p
, b
.p
, opcodebase
);
155 if(trace
) werrstr("\tline %lu, addr 0x%x, op %d %.10H", cur
.line
, cur
.addr
, op
, b
.p
);
156 if(op
>= opcodebase
){
157 a
= (op
- opcodebase
) / linerange
;
158 l
= (op
- opcodebase
) % linerange
+ linebase
;
160 cur
.addr
+= a
* quantum
;
161 if(trace
) werrstr(" +%d,%d\n", a
, l
);
165 werrstr("found wrong line mapping 0x%x for pc 0x%x", cur
.addr
, pc
);
166 /* This is an overzealous check. gcc can produce discontiguous ranges
167 and reorder statements, so it's possible for a future line to start
168 ahead of pc and still find a matching one. */
175 if(cur
.addr
> pc
&& !firstline
)
178 werrstr("buffer underflow in line mapping");
182 if(emit
.flags
& EndSequence
){
183 werrstr("found wrong line mapping 0x%x-0x%x for pc 0x%x", start
, cur
.addr
, pc
);
186 cur
.flags
&= ~(BasicDwarfBlock
|PrologueEnd
|EpilogueBegin
);
189 case 0: /* extended op code */
190 if(trace
) werrstr(" ext");
191 len
= dwarfget128(&b
);
193 if(b
.p
== nil
|| end
> b
.ep
|| end
< b
.p
|| len
< 1)
195 switch(dwarfget1(&b
)){
196 case 1: /* end sequence */
197 if(trace
) werrstr(" end\n");
198 cur
.flags
|= EndSequence
;
200 case 2: /* set address */
201 cur
.addr
= dwarfgetaddr(&b
);
202 if(trace
) werrstr(" set pc 0x%x\n", cur
.addr
);
204 case 3: /* define file */
205 newf
= malloc(nf
+1*sizeof(f
[0]));
207 RtlMoveMemory(newf
, f
, nf
*sizeof(f
[0]));
211 s
= dwarfgetstring(&b
);
215 if(trace
) werrstr(" def file %s\n", s
);
218 if(b
.p
== nil
|| b
.p
> end
)
223 if(trace
) werrstr(" emit\n");
225 case 2: /* advance pc */
227 if(trace
) werrstr(" advance pc + %lu\n", a
*quantum
);
228 cur
.addr
+= a
* quantum
;
230 case 3: /* advance line */
231 l
= dwarfget128s(&b
);
232 if(trace
) werrstr(" advance line + %ld\n", l
);
235 case 4: /* set file */
236 if(trace
) werrstr(" set file\n");
237 cur
.file
= dwarfget128s(&b
);
239 case 5: /* set column */
240 if(trace
) werrstr(" set column\n");
241 cur
.column
= dwarfget128(&b
);
243 case 6: /* negate stmt */
244 if(trace
) werrstr(" negate stmt\n");
247 case 7: /* set basic block */
248 if(trace
) werrstr(" set basic block\n");
249 cur
.flags
|= BasicDwarfBlock
;
251 case 8: /* const add pc */
252 a
= (255 - opcodebase
) / linerange
* quantum
;
253 if(trace
) werrstr(" const add pc + %d\n", a
);
256 case 9: /* fixed advance pc */
258 if(trace
) werrstr(" fixed advance pc + %d\n", a
);
261 case 10: /* set prologue end */
262 if(trace
) werrstr(" set prologue end\n");
263 cur
.flags
|= PrologueEnd
;
265 case 11: /* set epilogue begin */
266 if(trace
) werrstr(" set epilogue begin\n");
267 cur
.flags
|= EpilogueBegin
;
269 case 12: /* set isa */
270 if(trace
) werrstr(" set isa\n");
271 cur
.isa
= dwarfget128(&b
);
273 default: /* something new - skip it */
274 if(trace
) werrstr(" unknown %d\n", opcount
[op
]);
275 for(i
=0; i
<opcount
[op
]; i
++)
284 /* finally! the data we seek is in "emit" */
287 werrstr("invalid file index in mapping data");
293 /* skip over first emit.file-2 guys */
295 for(i
=emit
.file
-1; i
> 0 && b
.p
!=nil
&& *b
.p
!=0; i
--){
302 werrstr("problem parsing file data second time (cannot happen)");
307 werrstr("bad file index in mapping data");
312 s
= dwarfgetstring(&b
);
315 i
= dwarfget128(&b
); /* directory */
325 *cdir
= sym
.attrs
.compdir
;
330 for (x
= 1; b
.p
&& *b
.p
; x
++)
332 *dir
= dwarfgetstring(&b
);
340 if (dwarfenumunit(d
, unit
, &proc
) >= 0) {
341 dwarfnextsymat(d
, &proc
, 0);
342 while (dwarfnextsymat(d
, &proc
, 1) == 1) {
343 if (proc
.attrs
.tag
== TagSubprogram
&&
344 proc
.attrs
.have
.name
&&
345 proc
.attrs
.declfile
== emit
.file
&&
346 proc
.attrs
.declline
<= *line
&&
347 proc
.attrs
.declline
> lastline
) {
348 lastline
= proc
.attrs
.declline
;
350 *function
= malloc(strlen(proc
.attrs
.name
)+1);
351 strcpy(*function
, proc
.attrs
.name
);
358 for (i
= 0; i
< d
->pe
->nsymbols
; i
++) {
359 if (d
->pe
->symtab
[i
].address
> lastaddr
&&
360 d
->pe
->symtab
[i
].address
<= pc
- d
->pe
->imagebase
&&
361 d
->pe
->symtab
[i
].address
< d
->pe
->imagesize
) {
362 lastaddr
= d
->pe
->symtab
[i
].address
;
363 *function
= d
->pe
->symtab
[i
].name
;
367 // *sigh* we get unrelocated low_pc and high_pc because the dwarf symbols
368 // are not 'loaded' in the PE sense.
369 if (dwarflookupfn(d
, unit
, pc
, &proc
) >= 0) {
370 *function
= malloc(strlen(proc
.attrs
.name
)+1);
371 strcpy(*function
, proc
.attrs
.name
);
375 /* free at last, free at last */
380 werrstr("corrupted line mapping for 0x%x", pc
);