Skip to content

Commit 4520454

Browse files
author
grischka
committed
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.
1 parent cd75ca6 commit 4520454

File tree

5 files changed

+107
-43
lines changed

5 files changed

+107
-43
lines changed

libtcc.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1976,9 +1976,12 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ static const char help[] =
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,7 @@ ST_FUNC void tcc_debug_line(TCCState *s1)
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

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5500,25 +5500,12 @@ ST_FUNC void unary(void)
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)
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
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)
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)
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

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,7 @@ enum {
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 {
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)
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)
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)
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)
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)
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)
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)
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)
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 {

0 commit comments

Comments
 (0)