Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <mach.h>
4 #include "stabs.h"
6 static int
7 strcmpcolon(char *a, char *bcolon)
8 {
9 int i, len;
10 char *p;
12 p = strchr(bcolon, ':');
13 if(p == nil)
14 return strcmp(a, bcolon);
15 len = p-bcolon;
16 i = strncmp(a, bcolon, len);
17 if(i)
18 return i;
19 if(a[len] == 0)
20 return 0;
21 return 1;
22 }
24 static int
25 stabcvtsym(StabSym *stab, Symbol *sym, char *dir, char *file, int i)
26 {
27 char *p;
29 /*
30 * Zero out the : to avoid allocating a new name string.
31 * The type info can be found by looking past the NUL.
32 * This is going to get us in trouble...
33 */
34 if((p = strchr(stab->name, ':')) != nil)
35 *p++ = 0;
36 else
37 p = stab->name+strlen(stab->name)+1;
39 sym->name = stab->name;
40 sym->u.stabs.dir = dir;
41 sym->u.stabs.file = file;
42 sym->u.stabs.i = i;
43 switch(stab->type){
44 default:
45 return -1;
46 case N_FUN:
47 sym->class = CTEXT;
48 switch(*p){
49 default:
50 return -1;
51 case 'F': /* global function */
52 sym->type = 'T';
53 break;
54 case 'Q': /* static procedure */
55 case 'f': /* static function */
56 case 'I': /* nested procedure */
57 case 'J': /* nested function */
58 sym->type = 't';
59 break;
60 }
61 sym->loc.type = LADDR;
62 sym->loc.addr = stab->value;
63 break;
64 case N_GSYM:
65 case N_PSYM:
66 case N_LSYM:
67 case N_LCSYM:
68 sym->class = CDATA;
69 sym->loc.type = LADDR;
70 sym->loc.addr = stab->value;
71 switch(*p){
72 default:
73 return -1;
74 case 'S': /* file-scope static variable */
75 sym->type = 'd';
76 break;
77 case 'G': /* global variable */
78 sym->type = 'D';
79 sym->loc.type = LNONE;
80 break;
81 case 'r': /* register variable */
82 sym->class = CAUTO;
83 sym->type = 'a';
84 sym->loc.type = LREG;
85 sym->loc.reg = "XXX";
86 break;
87 case 's': /* local variable */
88 sym->class = CAUTO;
89 sym->type = 'a';
90 sym->loc.type = LOFFSET;
91 sym->loc.offset = stab->value;
92 sym->loc.reg = "XXX";
93 break;
94 case 'a': /* by reference */
95 case 'D': /* f.p. parameter */
96 case 'i': /* register parameter */
97 case 'p': /* "normal" parameter */
98 case 'P': /* register parameter */
99 case 'v': /* by reference */
100 case 'X': /* function return variable */
101 sym->class = CPARAM;
102 sym->type = 'p';
103 if(*p == 'i'){
104 sym->loc.type = LREG;
105 sym->loc.reg = "XXX";
106 }else{
107 sym->loc.type = LOFFSET;
108 sym->loc.offset = stab->value;
109 sym->loc.reg = "XXX";
111 break;
113 break;
115 return 0;
118 static int
119 stabssyminit(Fhdr *fp)
121 int i;
122 char *dir, *file;
123 Stab *stabs;
124 StabSym sym, lastfun;
125 Symbol s, *fun;
126 char **inc, **xinc;
127 int ninc, minc;
128 int locals, autos, params;
130 stabs = &fp->stabs;
131 if(stabs == nil){
132 werrstr("no stabs info");
133 return -1;
136 dir = nil;
137 file = nil;
138 inc = nil;
139 fun = nil;
140 ninc = 0;
141 minc = 0;
142 locals = 0;
143 params = 0;
144 autos = 0;
145 memset(&lastfun, 0, sizeof lastfun);
146 for(i=0; stabsym(stabs, i, &sym)>=0; i++){
147 switch(sym.type){
148 case N_SO:
149 if(sym.name == nil || *sym.name == 0){
150 file = nil;
151 break;
153 if(sym.name[strlen(sym.name)-1] == '/')
154 dir = sym.name;
155 else
156 file = sym.name;
157 break;
158 case N_BINCL:
159 if(ninc >= minc){
160 xinc = realloc(inc, (ninc+32)*sizeof(inc[0]));
161 if(xinc){
162 memset(xinc+ninc, 0, 32*sizeof(inc[0]));
163 inc = xinc;
165 ninc += 32;
167 if(ninc < minc)
168 inc[ninc] = sym.name;
169 ninc++;
170 break;
171 case N_EINCL:
172 if(ninc > 0)
173 ninc--;
174 break;
175 case N_EXCL:
176 /* condensed include - same effect as previous BINCL/EINCL pair */
177 break;
178 case N_GSYM: /* global variable */
179 /* only includes type, so useless for now */
180 break;
181 case N_FUN:
182 if(sym.name == nil){
183 /* marks end of function */
184 if(fun){
185 fun->hiloc.type = LADDR;
186 fun->hiloc.addr = fun->loc.addr + sym.value;
188 break;
190 if(fun && lastfun.value==sym.value && lastfun.name==sym.name){
191 fun->u.stabs.locals = i;
192 break;
194 /* create new symbol, add it */
195 lastfun = sym;
196 fun = nil;
197 if(stabcvtsym(&sym, &s, dir, file, i) < 0)
198 continue;
199 if((fun = _addsym(fp, &s)) == nil)
200 goto err;
201 locals = 0;
202 params = 0;
203 autos = 0;
204 break;
205 case N_PSYM:
206 case N_LSYM:
207 case N_LCSYM:
208 if(fun){
209 if(fun->u.stabs.frameptr == -1){
210 /*
211 * Try to distinguish functions with a real frame pointer
212 * from functions with a virtual frame pointer, based on
213 * whether the first parameter is in the right location and
214 * whether the autos have negative offsets.
216 * This heuristic works most of the time. On the 386, we
217 * cannot distinguish between a v. function with no autos
218 * but a frame of size 4 and a f.p. function with no autos and
219 * no frame. Anything else we'll get right.
221 * Another way to go about this would be to have
222 * mach-specific functions to inspect the function
223 * prologues when we're not sure. What we have
224 * already should be enough, though.
225 */
226 if(params==0 && sym.type == N_PSYM){
227 if(sym.value != 8 && sym.value >= 4){
228 /* XXX 386 specific, but let's find another system before generalizing */
229 fun->u.stabs.frameptr = 0;
230 fun->u.stabs.framesize = sym.value - 4;
232 }else if(sym.type == N_LSYM){
233 if(sym.value >= 0){
234 fun->u.stabs.frameptr = 0;
235 if(params)
236 fun->u.stabs.framesize = 8 - 4;
237 }else
238 fun->u.stabs.frameptr = 1;
241 if(sym.type == N_PSYM)
242 params++;
243 if(sym.type == N_LSYM)
244 autos++;
246 break;
248 case N_STSYM: /* static file-scope variable */
249 /* create new symbol, add it */
250 if(stabcvtsym(&sym, &s, dir, file, i) < 0)
251 continue;
252 if(_addsym(fp, &s) == nil)
253 goto err;
254 break;
257 free(inc);
258 return 0;
260 err:
261 free(inc);
262 return -1;
265 static int
266 stabspc2file(Fhdr *fhdr, ulong pc, char *buf, uint nbuf, ulong *pline)
268 int i;
269 Symbol *s;
270 StabSym ss;
271 ulong line, basepc;
272 Loc l;
274 l.type = LADDR;
275 l.addr = pc;
276 if((s = ffindsym(fhdr, l, CTEXT)) == nil
277 || stabsym(&fhdr->stabs, s->u.stabs.i, &ss) < 0)
278 return -1;
280 line = ss.desc;
281 basepc = ss.value;
282 for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){
283 if(ss.type == N_FUN && ss.name == nil)
284 break;
285 if(ss.type == N_SLINE){
286 if(basepc+ss.value > pc)
287 break;
288 else
289 line = ss.desc;
292 *pline = line;
293 if(s->u.stabs.dir)
294 snprint(buf, nbuf, "%s%s", s->u.stabs.dir, s->u.stabs.file);
295 else
296 snprint(buf, nbuf, "%s", s->u.stabs.file);
297 return 0;
300 static int
301 stabsline2pc(Fhdr *fhdr, ulong startpc, ulong line, ulong *pc)
303 int i, trigger;
304 Symbol *s;
305 StabSym ss;
306 ulong basepc;
307 Loc l;
309 l.type = LADDR;
310 l.addr = startpc;
311 if((s = ffindsym(fhdr, l, CTEXT)) == nil)
312 return -1;
314 trigger = 0;
315 line = ss.desc;
316 basepc = ss.value;
317 for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){
318 if(ss.type == N_FUN)
319 basepc = ss.value;
320 if(ss.type == N_SLINE){
321 if(basepc+ss.value >= startpc)
322 trigger = 1;
323 if(trigger && ss.desc >= line){
324 *pc = basepc+ss.value;
325 return 0;
329 return -1;
332 static int
333 stabslenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s)
335 int i;
336 StabSym ss;
338 for(i=p->u.stabs.locals; stabsym(&fhdr->stabs, i, &ss)>=0; i++){
339 if(ss.type == N_FUN && ss.name == nil)
340 break;
341 switch(ss.type){
342 case N_PSYM:
343 case N_LSYM:
344 case N_LCSYM:
345 if(name){
346 if(strcmpcolon(name, ss.name) != 0)
347 break;
348 }else if(l.type){
349 /* wait for now */
350 }else{
351 if(j-- > 0)
352 break;
354 if(stabcvtsym(&ss, s, p->u.stabs.dir, p->u.stabs.file, i) < 0)
355 return -1;
356 if(s->loc.type == LOFFSET){
357 if(p->u.stabs.frameptr == 0)
358 s->loc.reg = mach->sp;
359 else
360 s->loc.reg = mach->fp;
362 if(l.type && loccmp(&l, &s->loc) != 0)
363 break;
364 return 0;
367 return -1;
370 static Loc zl;
372 static int
373 stabslookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
375 return stabslenum(fhdr, p, name, 0, zl, s);
378 static int
379 stabsindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
381 return stabslenum(fhdr, p, nil, i, zl, s);
384 static int
385 stabsfindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
387 return stabslenum(fhdr, p, nil, 0, l, s);
390 int
391 symstabs(Fhdr *fp)
393 if(stabssyminit(fp) < 0)
394 return -1;
395 fp->pc2file = stabspc2file;
396 fp->line2pc = stabsline2pc;
397 fp->lookuplsym = stabslookuplsym;
398 fp->indexlsym = stabsindexlsym;
399 fp->findlsym = stabsfindlsym;
400 return 0;