History

win32: pe dwarf sections & option -g.pdb

On windows, create a .pdb file with option "-g.pdb" Such executables created by tcc can be debugged with "ollydbg" or "x64dbg" This currently relies on the 3rd party tool cv2pdb from https://github.com/rainers/cv2pdb which again relies on mspdbsrv.exe mspdbcore.dll msobj80.dll mspdb80.dll from a MSVC installation. cv2pdb.exe + the ms* files may be put in the path or in the same directory as tcc.exe.

grischka committed 3 years ago

Commit 45204541 parent cd75ca65 files · +107 −43Browse files

Unified · Split

5 files
  1. libtcc.c +4 −1
  2. tcc.c +3 −0
  3. tccdbg.c +1 −1
  4. tccgen.c +28 −29
  5. tccpe.c +71 −12
libtcc.c+4−1
@@ -1976,9 +1976,12 @@ dorun: · 1975 unmodified lines
19761976 case TCC_OPTION_g:
19771977 s->do_debug = 1;
19781978 s->dwarf = DWARF_VERSION;
1979−
19801979 if (strstart("dwarf", &optarg))
19811980 s->dwarf = (*optarg) ? (0 - atoi(optarg)) : DEFAULT_DWARF_VERSION;
1981+#ifdef TCC_TARGET_PE
1982+ else if (0 == strcmp(".pdb", optarg))
1983+ s->dwarf = 5, s->do_debug |= 16;
1984+#endif
19821985 break;
19831986 case TCC_OPTION_c:
19841987 x = TCC_OUTPUT_OBJ;
tcc.c+3−0
@@ -59,6 +59,9 @@ static const char help[] = · 58 unmodified lines
5959 "Debugger options:\n"
6060 " -g generate stab runtime debug info\n"
6161 " -gdwarf[-x] generate dwarf runtime debug info\n"
62+#ifdef TCC_TARGET_PE
63+ " -g.pdb create .pdb debug database\n"
64+#endif
6265 #ifdef CONFIG_TCC_BCHECK
6366 " -b compile with built-in memory and bounds checker (implies -g)\n"
6467 #endif
tccdbg.c+1−1
@@ -1086,7 +1086,7 @@ ST_FUNC void tcc_debug_line(TCCState *s1) · 1085 unmodified lines
10861086
10871087 if (!s1->do_debug)
10881088 return;
1089− if (cur_text_section != text_section)
1089+ if (cur_text_section != text_section || nocode_wanted)
10901090 return;
10911091 f = put_new_file(s1);
10921092 if (!f)
tccgen.c+28−29
@@ -5500,25 +5500,12 @@ ST_FUNC void unary(void) · 5499 unmodified lines
55005500 goto tok_identifier;
55015501 /* fall thru */
55025502 case TOK___FUNC__:
5503− {
5504− Section *sec;
5505− int len;
5506− /* special function name identifier */
5507− len = strlen(funcname) + 1;
5508− /* generate char[len] type */
5509− type.t = char_type.t;
5510− if (tcc_state->warn_write_strings & WARN_ON)
5511− type.t |= VT_CONSTANT;
5512− mk_pointer(&type);
5513− type.t |= VT_ARRAY;
5514− type.ref->c = len;
5515− sec = rodata_section;
5516− vpush_ref(&type, sec, sec->data_offset, len);
5517− if (!NODATA_WANTED)
5518− memcpy(section_ptr_add(sec, len), funcname, len);
5519− next();
5520− }
5521− break;
5503+ tok = TOK_STR;
5504+ cstr_reset(&tokcstr);
5505+ cstr_cat(&tokcstr, funcname, 0);
5506+ tokc.str.size = tokcstr.size;
5507+ tokc.str.data = tokcstr.data;
5508+ goto case_TOK_STR;
55225509 case TOK_LSTR:
55235510 #ifdef TCC_TARGET_PE
55245511 t = VT_SHORT | VT_UNSIGNED;
@@ -5527,6 +5514,7 @@ ST_FUNC void unary(void) · 2 unmodified lines
55275514 #endif
55285515 goto str_init;
55295516 case TOK_STR:
5517+ case_TOK_STR:
55305518 /* string parsing */
55315519 t = char_type.t;
55325520 str_init:
@@ -7767,7 +7755,7 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f · 2234 unmodified lines
77677755 CType *t1;
77687756
77697757 /* generate line number info */
7770− if (debug_modes && !p->sec)
7758+ if (debug_modes && !(flags & DIF_SIZE_ONLY) && !p->sec)
77717759 tcc_debug_line(tcc_state), tcc_tcov_check_line (tcc_state, 1);
77727760
77737761 if (!(flags & DIF_HAVE_ELEM) && tok != '{' &&
@@ -8288,50 +8276,60 @@ static void gen_function(Sym *sym) · 514 unmodified lines
82888276 struct scope f = { 0 };
82898277 cur_scope = root_scope = &f;
82908278 nocode_wanted = 0;
8279+
82918280 ind = cur_text_section->data_offset;
82928281 if (sym->a.aligned) {
82938282 size_t newoff = section_add(cur_text_section, 0,
82948283 1 << (sym->a.aligned - 1));
82958284 gen_fill_nops(newoff - ind);
82968285 }
8286+
8287+ funcname = get_tok_str(sym->v, NULL);
8288+ func_ind = ind;
8289+ func_vt = sym->type.ref->type;
8290+ func_var = sym->type.ref->f.func_type == FUNC_ELLIPSIS;
8291+
82978292 /* NOTE: we patch the symbol size later */
82988293 put_extern_sym(sym, cur_text_section, ind, 0);
8294+
82998295 if (sym->type.ref->f.func_ctor)
83008296 add_array (tcc_state, ".init_array", sym->c);
83018297 if (sym->type.ref->f.func_dtor)
83028298 add_array (tcc_state, ".fini_array", sym->c);
83038299
8304− funcname = get_tok_str(sym->v, NULL);
8305− func_ind = ind;
8306− func_vt = sym->type.ref->type;
8307− func_var = sym->type.ref->f.func_type == FUNC_ELLIPSIS;
8308−
83098300 /* put debug symbol */
83108301 tcc_debug_funcstart(tcc_state, sym);
8302+
83118303 /* push a dummy symbol to enable local sym storage */
83128304 sym_push2(&local_stack, SYM_FIELD, 0, 0);
83138305 local_scope = 1; /* for function parameters */
83148306 gfunc_prolog(sym);
83158307 tcc_debug_prolog_epilog(tcc_state, 0);
8308+
83168309 local_scope = 0;
83178310 rsym = 0;
83188311 clear_temp_local_var_list();
83198312 func_vla_arg(sym);
83208313 block(0);
83218314 gsym(rsym);
8315+
83228316 nocode_wanted = 0;
83238317 /* reset local stack */
83248318 pop_local_syms(NULL, 0);
83258319 tcc_debug_prolog_epilog(tcc_state, 1);
83268320 gfunc_epilog();
8321+
8322+ /* end of function */
8323+ tcc_debug_funcend(tcc_state, ind - func_ind);
8324+
8325+ /* patch symbol size */
8326+ elfsym(sym)->st_size = ind - func_ind;
8327+
83278328 cur_text_section->data_offset = ind;
83288329 local_scope = 0;
83298330 label_pop(&global_label_stack, NULL, 0);
83308331 sym_pop(&all_cleanups, NULL, 0);
8331− /* patch symbol size */
8332− elfsym(sym)->st_size = ind - func_ind;
8333− /* end of function */
8334− tcc_debug_funcend(tcc_state, ind - func_ind);
8332+
83358333 /* It's better to crash than to generate wrong code */
83368334 cur_text_section = NULL;
83378335 funcname = ""; /* for safety */
@@ -8341,6 +8339,7 @@ static void gen_function(Sym *sym) · 3 unmodified lines
83418339 func_ind = -1;
83428340 nocode_wanted = DATA_ONLY_WANTED;
83438341 check_vstack();
8342+
83448343 /* do this after funcend debug info */
83458344 next();
83468345 }
tccpe.c+71−12
@@ -301,8 +301,7 @@ enum { · 300 unmodified lines
301301 sec_pdata ,
302302 sec_other ,
303303 sec_rsrc ,
304− sec_stab ,
305− sec_stabstr ,
304+ sec_debug ,
306305 sec_reloc ,
307306 sec_last
308307 };
@@ -475,9 +474,9 @@ struct pe_file { · 166 unmodified lines
475474 unsigned pos;
476475 };
477476
478−static int pe_fwrite(void *data, int len, struct pe_file *pf)
477+static int pe_fwrite(const void *data, int len, struct pe_file *pf)
479478 {
480− WORD *p = data;
479+ const WORD *p = data;
481480 DWORD sum;
482481 int ret, i;
483482 pf->pos += (ret = fwrite(data, 1, len, pf->op));
@@ -502,6 +501,51 @@ static void pe_fpad(struct pe_file *pf, DWORD new_pos) · 18 unmodified lines
502501 pf->pos = new_pos;
503502 }
504503
504+/*----------------------------------------------------------------------------*/
505+/* PE-DWARF/COFF support
506+ does not work with a mingw-gdb really but works with cv2pdb
507+ (https://github.com/rainers/cv2pdb) */
508+
509+#define N_COFF_SYMS 0
510+
511+static const char dwarf_secs[] =
512+{
513+ ".debug_info\0"
514+ ".debug_abbrev\0"
515+ ".debug_line\0"
516+ ".debug_aranges\0"
517+ ".debug_str\0"
518+ ".debug_line_str\0"
519+};
520+
521+static const unsigned coff_strtab_size = 4 + sizeof dwarf_secs - 1;
522+
523+static int pe_put_long_secname(char *secname, const char *name)
524+{
525+ const char *d = dwarf_secs;
526+ do {
527+ if (0 == strcmp(d, name)) {
528+ sprintf(secname, "/%d", (int)(d - dwarf_secs + 4));
529+ return 1;
530+ }
531+ d = strchr(d, 0) + 1;
532+ } while (*d);
533+ return 0;
534+}
535+
536+static void pe_create_pdb(TCCState *s1, const char *exename)
537+{
538+ char buf[300]; int r;
539+ snprintf(buf, sizeof buf, "cv2pdb.exe %s", exename);
540+ r = system(buf);
541+ strcpy(tcc_fileextension(strcpy(buf, exename)), ".pdb");
542+ if (r) {
543+ tcc_error_noabort("could not create '%s'\n(need working cv2pdb from https://github.com/rainers/cv2pdb)", buf);
544+ } else if (s1->verbose) {
545+ printf("<- %s\n", buf);
546+ }
547+}
548+
505549 /*----------------------------------------------------------------------------*/
506550 static int pe_write(struct pe_info *pe)
507551 {
@@ -616,6 +660,7 @@ static int pe_write(struct pe_info *pe) · 108 unmodified lines
616660 struct section_info *si;
617661 IMAGE_SECTION_HEADER *psh;
618662 TCCState *s1 = pe->s1;
663+ int need_strtab = 0;
619664
620665 pf.op = fopen(pe->filename, "wb");
621666 if (NULL == pf.op)
@@ -686,6 +731,8 @@ static int pe_write(struct pe_info *pe) · 64 unmodified lines
686731 }
687732
688733 memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name));
734+ if (si->cls == sec_debug)
735+ need_strtab += pe_put_long_secname(psh->Name, sh_name);
689736
690737 psh->Characteristics = si->pe_flags;
691738 psh->VirtualAddress = addr;
@@ -715,7 +762,10 @@ static int pe_write(struct pe_info *pe) · 23 unmodified lines
715762 if (PE_DLL == pe->type)
716763 pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
717764 pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics;
718−
765+ if (need_strtab) {
766+ pe_header.filehdr.PointerToSymbolTable = file_offset;
767+ pe_header.filehdr.NumberOfSymbols = N_COFF_SYMS;
768+ }
719769 pe_fwrite(&pe_header, sizeof pe_header, &pf);
720770 for (i = 0; i < pe->sec_count; ++i)
721771 pe_fwrite(&pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER), &pf);
@@ -736,6 +786,13 @@ static int pe_write(struct pe_info *pe) · 14 unmodified lines
736786 pe_fpad(&pf, file_offset);
737787 }
738788
789+ if (need_strtab) {
790+ /* create a tiny COFF string table with the long section names */
791+ pe_fwrite(&coff_strtab_size, sizeof coff_strtab_size, &pf);
792+ pe_fwrite(dwarf_secs, sizeof dwarf_secs - 1, &pf);
793+ file_offset = pf.pos;
794+ }
795+
739796 pf.sum += file_offset;
740797 fseek(pf.op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
741798 pe_fwrite(&pf.sum, sizeof (DWORD), &pf);
@@ -750,6 +807,8 @@ static int pe_write(struct pe_info *pe) · 8 unmodified lines
750807 if (pe->s1->verbose)
751808 printf("<- %s (%u bytes)\n", pe->filename, (unsigned)file_offset);
752809
810+ if (s1->do_debug & 16)
811+ pe_create_pdb(s1, pe->filename);
753812 return 0;
754813 }
755814
@@ -1072,12 +1131,12 @@ static int pe_section_class(Section *s) · 316 unmodified lines
10721131 type = s->sh_type;
10731132 flags = s->sh_flags;
10741133 name = s->name;
1075− if (0 == memcmp(name, ".stab", 5)) {
1076− if (0 == s->s1->do_debug)
1077− return sec_last;
1078− return name[5] ? sec_stabstr : sec_stab;
1079− }
1080− if (flags & SHF_ALLOC) {
1134+
1135+ if (0 == memcmp(name, ".stab", 5) || 0 == memcmp(name, ".debug_", 7)) {
1136+ if (s->s1->do_debug)
1137+ return sec_debug;
1138+
1139+ } else if (flags & SHF_ALLOC) {
10811140 if (type == SHT_PROGBITS
10821141 || type == SHT_INIT_ARRAY
10831142 || type == SHT_FINI_ARRAY) {
@@ -1135,7 +1194,7 @@ static int pe_assign_addresses (struct pe_info *pe) · 51 unmodified lines
11351194 if (PE_MERGE_DATA && c == sec_bss)
11361195 c = sec_data;
11371196
1138− if (si && c == si->cls) {
1197+ if (si && c == si->cls && c != sec_debug) {
11391198 /* merge with previous section */
11401199 s->sh_addr = addr = ((addr - 1) | (16 - 1)) + 1;
11411200 } else {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t