• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Stabs debugging format
3  *
4  *  Copyright (C) 2003-2007  Michael Urman
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include <util.h>
28 
29 #include <libyasm.h>
30 
31 typedef enum {
32     N_UNDF = 0x00,      /* Undefined */
33     N_GSYM = 0x20,      /* Global symbol */
34     N_FNAME = 0x22,     /* Function name (BSD Fortran) */
35     N_FUN = 0x24,       /* Function name or Text segment variable */
36     N_STSYM = 0x26,     /* Data segment file-scope variable */
37     N_LCSYM = 0x28,     /* BSS segment file-scope variable */
38     N_MAIN = 0x2a,      /* Name of main routine */
39     N_ROSYM = 0x2c,     /* Variable in .rodata section */
40     N_PC = 0x30,        /* Global symbol (Pascal) */
41     N_SYMS = 0x32,      /* Number of symbols (Ultrix V4.0) */
42     N_NOMAP = 0x34,     /* No DST map */
43     N_OBJ = 0x38,       /* Object file (Solaris2) */
44     N_OPT = 0x3c,       /* Debugger options (Solaris2) */
45     N_RSYM = 0x40,      /* Register variable */
46     N_M2C = 0x42,       /* Modula-2 compilation unit */
47     N_SLINE = 0x44,     /* Line numbers in .text segment */
48     N_DSLINE = 0x46,    /* Line numbers in .data segment */
49     N_BSLINE = 0x48,    /* Line numbers in .bss segment */
50     N_BROWS = 0x48,     /* Source code .cb file's path */
51     N_DEFD = 0x4a,      /* GNU Modula-2 definition module dependency */
52     N_FLINE = 0x4c,     /* Function start/body/end line numbers (Solaris2) */
53     N_EHDECL = 0x50,    /* GNU C++ exception variable */
54     N_MOD2 = 0x50,      /* Modula2 info for imc (Ultrix V4.0) */
55     N_CATCH = 0x54,     /* GNU C++ catch clause */
56     N_SSYM = 0x60,      /* Structure or union element */
57     N_ENDM = 0x62,      /* Last stab for module (Solaris2) */
58     N_SO = 0x64,        /* Path and name of source files */
59     N_LSYM = 0x80,      /* Stack variable */
60     N_BINCL = 0x84,     /* Beginning of include file */
61     N_SOL = 0x84,       /* Name of include file */
62     N_PSYM = 0xa0,      /* Parameter variable */
63     N_EINCL = 0xa2,     /* End of include file */
64     N_ENTRY = 0xa4,     /* Alternate entry point */
65     N_LBRAC = 0xc0,     /* Beginning of lexical block */
66     N_EXCL = 0xc2,      /* Placeholder for a deleted include file */
67     N_SCOPE = 0xc4,     /* Modula 2 scope info (Sun) */
68     N_RBRAC = 0xe0,     /* End of lexical block */
69     N_BCOMM = 0xe2,     /* Begin named common block */
70     N_ECOMM = 0xe4,     /* End named common block */
71     N_ECOML = 0xe8,     /* Member of common block */
72     N_WITH = 0xea,      /* Pascal with statement: type,,0,0,offset (Solaris2) */
73     N_NBTEXT = 0xf0,    /* Gould non-base registers */
74     N_NBDATA = 0xf2,    /* Gould non-base registers */
75     N_NBBSS = 0xf4,     /* Gould non-base registers */
76     N_NBSTS = 0xf6,     /* Gould non-base registers */
77     N_NBLCS = 0xf8      /* Gould non-base registers */
78 } stabs_stab_type;
79 
80 typedef struct yasm_dbgfmt_stabs {
81     yasm_dbgfmt_base dbgfmt;        /* base structure */
82 } yasm_dbgfmt_stabs;
83 
84 typedef struct {
85     unsigned long lastline;     /* track line and file of bytecodes */
86     unsigned long curline;
87     const char *lastfile;
88     const char *curfile;
89 
90     unsigned int stablen;       /* size of a stab for current machine */
91     unsigned long stabcount;    /* count stored stabs; doesn't include first */
92 
93     yasm_section *stab;         /* sections to which stabs, stabstrs appended */
94     yasm_section *stabstr;
95 
96     yasm_bytecode *basebc;      /* base bytecode from which to track SLINEs */
97 
98     yasm_object *object;
99     yasm_linemap *linemap;
100     yasm_errwarns *errwarns;
101 } stabs_info;
102 
103 typedef struct {
104     /*@null@*/ yasm_bytecode *bcstr;    /* bytecode in stabstr for string */
105     stabs_stab_type type;               /* stab type: N_* */
106     unsigned char other;                /* unused, but stored here anyway */
107     unsigned short desc;                /* description element of a stab */
108     /*@null@*/ yasm_symrec *symvalue;   /* value element needing relocation */
109     /*@null@*/yasm_bytecode *bcvalue;   /* relocated stab's bytecode */
110     unsigned long value;                /* fallthrough value if above NULL */
111 } stabs_stab;
112 
113 /* Bytecode callback function prototypes */
114 
115 static void stabs_bc_str_destroy(void *contents);
116 static void stabs_bc_str_print(const void *contents, FILE *f, int
117                                indent_level);
118 static int stabs_bc_str_calc_len
119     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
120 static int stabs_bc_str_tobytes
121     (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
122      yasm_output_value_func output_value,
123      /*@null@*/ yasm_output_reloc_func output_reloc);
124 
125 static void stabs_bc_stab_destroy(void *contents);
126 static void stabs_bc_stab_print(const void *contents, FILE *f, int
127                                 indent_level);
128 static int stabs_bc_stab_calc_len
129     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
130 static int stabs_bc_stab_tobytes
131     (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
132      yasm_output_value_func output_value,
133      /*@null@*/ yasm_output_reloc_func output_reloc);
134 
135 /* Bytecode callback structures */
136 
137 static const yasm_bytecode_callback stabs_bc_str_callback = {
138     stabs_bc_str_destroy,
139     stabs_bc_str_print,
140     yasm_bc_finalize_common,
141     NULL,
142     stabs_bc_str_calc_len,
143     yasm_bc_expand_common,
144     stabs_bc_str_tobytes,
145     0
146 };
147 
148 static const yasm_bytecode_callback stabs_bc_stab_callback = {
149     stabs_bc_stab_destroy,
150     stabs_bc_stab_print,
151     yasm_bc_finalize_common,
152     NULL,
153     stabs_bc_stab_calc_len,
154     yasm_bc_expand_common,
155     stabs_bc_stab_tobytes,
156     0
157 };
158 
159 yasm_dbgfmt_module yasm_stabs_LTX_dbgfmt;
160 
161 
162 static /*@null@*/ /*@only@*/ yasm_dbgfmt *
stabs_dbgfmt_create(yasm_object * object)163 stabs_dbgfmt_create(yasm_object *object)
164 {
165     yasm_dbgfmt_stabs *dbgfmt_stabs = yasm_xmalloc(sizeof(yasm_dbgfmt_stabs));
166     dbgfmt_stabs->dbgfmt.module = &yasm_stabs_LTX_dbgfmt;
167     return (yasm_dbgfmt *)dbgfmt_stabs;
168 }
169 
170 static void
stabs_dbgfmt_destroy(yasm_dbgfmt * dbgfmt)171 stabs_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt)
172 {
173     yasm_xfree(dbgfmt);
174 }
175 
176 /* Create and add a new strtab-style string bytecode to a section, updating
177  * offset on insertion; no optimization necessary */
178 /* Copies the string, so you must still free yours as normal */
179 static yasm_bytecode *
stabs_dbgfmt_append_bcstr(yasm_section * sect,const char * str)180 stabs_dbgfmt_append_bcstr(yasm_section *sect, const char *str)
181 {
182     yasm_bytecode *bc;
183 
184     bc = yasm_bc_create_common(&stabs_bc_str_callback, yasm__xstrdup(str), 0);
185     bc->len = (unsigned long)(strlen(str)+1);
186     bc->offset = yasm_bc_next_offset(yasm_section_bcs_last(sect));
187 
188     yasm_section_bcs_append(sect, bc);
189 
190     return bc;
191 }
192 
193 /* Create and add a new stab bytecode to a section, updating offset on
194  * insertion; no optimization necessary. */
195 /* Requires a string bytecode, or NULL, for its string entry */
196 static stabs_stab *
stabs_dbgfmt_append_stab(stabs_info * info,yasm_section * sect,yasm_bytecode * bcstr,stabs_stab_type type,unsigned long desc,yasm_symrec * symvalue,yasm_bytecode * bcvalue,unsigned long value)197 stabs_dbgfmt_append_stab(stabs_info *info, yasm_section *sect,
198                          /*@null@*/ yasm_bytecode *bcstr, stabs_stab_type type,
199                          unsigned long desc, /*@null@*/ yasm_symrec *symvalue,
200                          /*@null@*/ yasm_bytecode *bcvalue, unsigned long value)
201 {
202     yasm_bytecode *bc;
203     stabs_stab *stab = yasm_xmalloc(sizeof(stabs_stab));
204 
205     stab->other = 0;
206     stab->bcstr = bcstr;
207     stab->type = type;
208     stab->desc = (unsigned short)desc;
209     stab->symvalue = symvalue;
210     stab->bcvalue = bcvalue;
211     stab->value = value;
212 
213     bc = yasm_bc_create_common(&stabs_bc_stab_callback, stab,
214                                bcvalue ? bcvalue->line : 0);
215     bc->len = info->stablen;
216     bc->offset = yasm_bc_next_offset(yasm_section_bcs_last(sect));
217 
218     yasm_section_bcs_append(sect, bc);
219 
220     info->stabcount++;
221     return stab;
222 }
223 
224 static void
stabs_dbgfmt_generate_n_fun(stabs_info * info,yasm_bytecode * bc)225 stabs_dbgfmt_generate_n_fun(stabs_info *info, yasm_bytecode *bc)
226 {
227     /* check all syms at this bc for potential function syms */
228     int bcsym;
229     for (bcsym=0; bc->symrecs && bc->symrecs[bcsym]; bcsym++)
230     {
231         char *str;
232         yasm_symrec *sym = bc->symrecs[bcsym];
233         const char *name = yasm_symrec_get_name(sym);
234 
235         /* best guess algorithm - ignore labels containing a . or $ */
236         if (strchr(name, '.') || strchr(name, '$'))
237             continue;
238 
239         /* if a function, update basebc, and output a funcname:F1 stab */
240         info->basebc = bc;
241 
242         str = yasm_xmalloc(strlen(name)+4);
243         strcpy(str, name);
244         strcat(str, ":F1");
245         stabs_dbgfmt_append_stab(info, info->stab,
246                                  stabs_dbgfmt_append_bcstr(info->stabstr, str),
247                                  N_FUN, 0, sym, info->basebc, 0);
248         yasm_xfree(str);
249         break;
250     }
251 }
252 
253 static int
stabs_dbgfmt_generate_bcs(yasm_bytecode * bc,void * d)254 stabs_dbgfmt_generate_bcs(yasm_bytecode *bc, void *d)
255 {
256     stabs_info *info = (stabs_info *)d;
257     yasm_linemap_lookup(info->linemap, bc->line, &info->curfile,
258                         &info->curline);
259 
260     /* check for new function */
261     stabs_dbgfmt_generate_n_fun(info, bc);
262 
263     if (info->lastfile != info->curfile) {
264         info->lastline = 0; /* new file, so line changes */
265         /*stabs_dbgfmt_append_stab(info, info->stab,
266             stabs_dbgfmt_append_bcstr(info->stabstr, info->curfile),
267             N_SOL, 0, NULL, bc, 0);*/
268     }
269 
270     /* output new line stabs if there's a basebc (known function) */
271     if (info->basebc != NULL && info->curline != info->lastline) {
272         info->lastline = bc->line;
273         stabs_dbgfmt_append_stab(info, info->stab, NULL, N_SLINE,
274                                  info->curline, NULL, NULL,
275                                  bc->offset - info->basebc->offset);
276     }
277 
278     info->lastline = info->curline;
279     info->lastfile = info->curfile;
280 
281     return 0;
282 }
283 
284 static int
stabs_dbgfmt_generate_sections(yasm_section * sect,void * d)285 stabs_dbgfmt_generate_sections(yasm_section *sect, /*@null@*/ void *d)
286 {
287     stabs_info *info = (stabs_info *)d;
288     const char *sectname=yasm_section_get_name(sect);
289 
290     /* each section has a different base symbol */
291     info->basebc = NULL;
292 
293     /* handle first (pseudo) bc separately */
294     stabs_dbgfmt_generate_n_fun(d, yasm_section_bcs_first(sect));
295 
296     yasm_section_bcs_traverse(sect, info->errwarns, d,
297                               stabs_dbgfmt_generate_bcs);
298 
299     if (yasm__strcasecmp(sectname, ".text")==0) {
300         /* Close out last function by appending a null SO stab after last bc */
301         yasm_bytecode *bc = yasm_section_bcs_last(sect);
302         yasm_symrec *sym =
303             yasm_symtab_define_label(info->object->symtab, ".n_so", bc, 1,
304                                      bc->line);
305         stabs_dbgfmt_append_stab(info, info->stab, 0, N_SO, 0, sym, bc, 0);
306     }
307 
308     return 1;
309 }
310 
311 static void
stabs_dbgfmt_generate(yasm_object * object,yasm_linemap * linemap,yasm_errwarns * errwarns)312 stabs_dbgfmt_generate(yasm_object *object, yasm_linemap *linemap,
313                       yasm_errwarns *errwarns)
314 {
315     stabs_info info;
316     int new;
317     yasm_bytecode *dbgbc;
318     stabs_stab *stab;
319     yasm_bytecode *filebc, *nullbc, *laststr, *firstbc;
320     yasm_symrec *firstsym;
321     yasm_section *stext;
322 
323     /* Stablen is determined by arch/machine */
324     if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") == 0) {
325         info.stablen = 12;
326     }
327     else /* unknown machine; generate nothing */
328         return;
329 
330     info.object = object;
331     info.linemap = linemap;
332     info.errwarns = errwarns;
333     info.lastline = 0;
334     info.stabcount = 0;
335     info.stab = yasm_object_get_general(object, ".stab", 4, 0, 0, &new, 0);
336     if (!new) {
337         yasm_bytecode *last = yasm_section_bcs_last(info.stab);
338         if (last == NULL) {
339             yasm_error_set(YASM_ERROR_GENERAL,
340                 N_("stabs debugging conflicts with user-defined section .stab"));
341             yasm_errwarn_propagate(errwarns,
342                                    yasm_section_bcs_first(info.stab)->line);
343         } else {
344             yasm_warn_set(YASM_WARN_GENERAL,
345                 N_("stabs debugging overrides empty section .stab"));
346             yasm_errwarn_propagate(errwarns, 0);
347         }
348     }
349 
350     info.stabstr =
351         yasm_object_get_general(object, ".stabstr", 1, 0, 0, &new, 0);
352     if (!new) {
353         yasm_bytecode *last = yasm_section_bcs_last(info.stabstr);
354         if (last == NULL) {
355             yasm_error_set(YASM_ERROR_GENERAL,
356                 N_("stabs debugging conflicts with user-defined section .stabstr"));
357             yasm_errwarn_propagate(errwarns,
358                                    yasm_section_bcs_first(info.stab)->line);
359         } else {
360             yasm_warn_set(YASM_WARN_GENERAL,
361                 N_("stabs debugging overrides empty section .stabstr"));
362             yasm_errwarn_propagate(errwarns, 0);
363         }
364     }
365 
366     /* initial pseudo-stab */
367     stab = yasm_xmalloc(sizeof(stabs_stab));
368     dbgbc = yasm_bc_create_common(&stabs_bc_stab_callback, stab, 0);
369     dbgbc->len = info.stablen;
370     dbgbc->offset = 0;
371     yasm_section_bcs_append(info.stab, dbgbc);
372 
373     /* initial strtab bytecodes */
374     nullbc = stabs_dbgfmt_append_bcstr(info.stabstr, "");
375     filebc = stabs_dbgfmt_append_bcstr(info.stabstr, object->src_filename);
376 
377     stext = yasm_object_find_general(object, ".text");
378     firstsym = yasm_symtab_use(object->symtab, ".text", 0);
379     firstbc = yasm_section_bcs_first(stext);
380     /* N_SO file stab */
381     stabs_dbgfmt_append_stab(&info, info.stab, filebc, N_SO, 0,
382                              firstsym, firstbc, 0);
383 
384     yasm_object_sections_traverse(object, (void *)&info,
385                                   stabs_dbgfmt_generate_sections);
386 
387     /* fill initial pseudo-stab's fields */
388     laststr = yasm_section_bcs_last(info.stabstr);
389     if (laststr == NULL)
390         yasm_internal_error(".stabstr has no entries");
391 
392     stab->bcvalue = NULL;
393     stab->symvalue = NULL;
394     stab->value = yasm_bc_next_offset(laststr);
395     stab->bcstr = filebc;
396     stab->type = N_UNDF;
397     stab->other = 0;
398     if (info.stabcount > 0xffff) {
399         yasm_warn_set(YASM_WARN_GENERAL, N_("over 65535 stabs"));
400         yasm_errwarn_propagate(errwarns, 0);
401         stab->desc = 0xffff;
402     } else
403         stab->desc = (unsigned short)info.stabcount;
404 }
405 
406 static int
stabs_bc_stab_tobytes(yasm_bytecode * bc,unsigned char ** bufp,unsigned char * bufstart,void * d,yasm_output_value_func output_value,yasm_output_reloc_func output_reloc)407 stabs_bc_stab_tobytes(yasm_bytecode *bc, unsigned char **bufp,
408                       unsigned char *bufstart, void *d,
409                       yasm_output_value_func output_value,
410                       yasm_output_reloc_func output_reloc)
411 {
412     /* This entire function, essentially the core of rendering stabs to a file,
413      * needs to become endian aware.  Size appears not to be an issue, as known
414      * 64-bit systems use truncated values in 32-bit fields. */
415 
416     const stabs_stab *stab = (const stabs_stab *)bc->contents;
417     unsigned char *buf = *bufp;
418 
419     YASM_WRITE_32_L(buf, stab->bcstr ? stab->bcstr->offset : 0);
420     YASM_WRITE_8(buf, stab->type);
421     YASM_WRITE_8(buf, stab->other);
422     YASM_WRITE_16_L(buf, stab->desc);
423 
424     if (stab->symvalue != NULL) {
425         bc->offset += 8;
426         output_reloc(stab->symvalue, bc, buf, 4, 32, 0, d);
427         bc->offset -= 8;
428         buf += 4;
429     }
430     else if (stab->bcvalue != NULL) {
431         YASM_WRITE_32_L(buf, stab->bcvalue->offset);
432     }
433     else {
434         YASM_WRITE_32_L(buf, stab->value);
435     }
436 
437     *bufp = buf;
438     return 0;
439 }
440 
441 static int
stabs_bc_str_tobytes(yasm_bytecode * bc,unsigned char ** bufp,unsigned char * bufstart,void * d,yasm_output_value_func output_value,yasm_output_reloc_func output_reloc)442 stabs_bc_str_tobytes(yasm_bytecode *bc, unsigned char **bufp,
443                      unsigned char *bufstart, void *d,
444                      yasm_output_value_func output_value,
445                      yasm_output_reloc_func output_reloc)
446 {
447     const char *str = (const char *)bc->contents;
448     unsigned char *buf = *bufp;
449 
450     strcpy((char *)buf, str);
451     buf += strlen(str)+1;
452 
453     *bufp = buf;
454     return 0;
455 }
456 
457 static void
stabs_bc_stab_destroy(void * contents)458 stabs_bc_stab_destroy(void *contents)
459 {
460     yasm_xfree(contents);
461 }
462 
463 static void
stabs_bc_str_destroy(void * contents)464 stabs_bc_str_destroy(void *contents)
465 {
466     yasm_xfree(contents);
467 }
468 
469 static void
stabs_bc_stab_print(const void * contents,FILE * f,int indent_level)470 stabs_bc_stab_print(const void *contents, FILE *f, int indent_level)
471 {
472     const stabs_stab *stab = (const stabs_stab *)contents;
473     const char *str = "";
474     fprintf(f, "%*s.stabs \"%s\", 0x%x, 0x%x, 0x%x, 0x%lx\n",
475             indent_level, "", str, stab->type, stab->other, stab->desc,
476             stab->bcvalue ? stab->bcvalue->offset : stab->value);
477 }
478 
479 static void
stabs_bc_str_print(const void * contents,FILE * f,int indent_level)480 stabs_bc_str_print(const void *contents, FILE *f, int indent_level)
481 {
482     fprintf(f, "%*s\"%s\"\n", indent_level, "", (const char *)contents);
483 }
484 
485 static int
stabs_bc_stab_calc_len(yasm_bytecode * bc,yasm_bc_add_span_func add_span,void * add_span_data)486 stabs_bc_stab_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
487                        void *add_span_data)
488 {
489     yasm_internal_error(N_("tried to resolve a stabs stab bytecode"));
490     /*@notreached@*/
491     return 0;
492 }
493 
494 static int
stabs_bc_str_calc_len(yasm_bytecode * bc,yasm_bc_add_span_func add_span,void * add_span_data)495 stabs_bc_str_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
496                       void *add_span_data)
497 {
498     yasm_internal_error(N_("tried to resolve a stabs str bytecode"));
499     /*@notreached@*/
500     return 0;
501 }
502 
503 /* Define dbgfmt structure -- see dbgfmt.h for details */
504 yasm_dbgfmt_module yasm_stabs_LTX_dbgfmt = {
505     "Stabs debugging format",
506     "stabs",
507     NULL,       /* no directives */
508     stabs_dbgfmt_create,
509     stabs_dbgfmt_destroy,
510     stabs_dbgfmt_generate
511 };
512