mirror of
https://github.com/mirror/tinycc.git
synced 2024-12-24 03:40:09 +08:00
Add dwarf support
The new gcc12 release does not support stabs any more. This was a good reason to add support for dwarf. The stabs code still works and is used if configure option --dwarf is not used. Tested on x86_64, i386, arm, arm64, riscv64 with dwarf-5. Some debuggers may not support dwarf-5. Try using older dwarf versions i that case. The tccmacho.c code probably need some support for dwarf. arm-gen.c, arm64-gen.c, i386-gen.c, riscv64-gen.c, x86_64-gen. - fix get_sym_ref symbol size arm-link.c, arm64-link.c, i386-link.c, riscv64-link.c, x86_64-link.c - add R_DATA_32U libtcc.c: - parse -gdwarf option tcc.c: - add dwarf option tcc.h: - add dwarf option and sections tccelf.c: - init dwarf sections - avoid adding sh_addr for dwarf sections - remove dwarf relocs for output dll - add dwarf sections for tccrun tccgen.c: - add dwarf defines + global data - add dwarf_* functions - mix dwarf code with stabs code - a trick is used to emit function name in .debug_line section so only this section has to be parsed instead of .debug_info and .debug_abbrev. - fix init debug_modes tccrun.c: - add dwarf sections in rt_context - init them in tcc_run - add new dwarf code rt_printline_dwarf to find file/function dwarf.h: - New file tcc-doc.texi: - document dwarf configure: - add dwarf option lib/Makefile - change -gstabs into -gdwarf lib/bt-exe.c, tests/tests2/Makefile, tests/tests2/126_bound_global: - Add __bound_init call - Add new testcase to test it
This commit is contained in:
parent
d3e940c71c
commit
2f2708a769
1
.gitignore
vendored
1
.gitignore
vendored
@ -24,6 +24,7 @@ config*.h
|
||||
config*.mak
|
||||
config.texi
|
||||
conftest*
|
||||
c2str
|
||||
tags
|
||||
TAGS
|
||||
tcc.1
|
||||
|
@ -866,7 +866,7 @@ static void gen_bounds_epilog(void)
|
||||
*bounds_ptr = 0;
|
||||
|
||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
func_bound_offset, PTR_SIZE);
|
||||
|
||||
/* generate bound local allocation */
|
||||
if (offset_modified) {
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
/* relocation type for 32 bit data relocation */
|
||||
#define R_DATA_32 R_ARM_ABS32
|
||||
#define R_DATA_32U R_ARM_ABS32
|
||||
#define R_DATA_PTR R_ARM_ABS32
|
||||
#define R_JMP_SLOT R_ARM_JUMP_SLOT
|
||||
#define R_GLOB_DAT R_ARM_GLOB_DAT
|
||||
|
@ -710,7 +710,7 @@ static void gen_bounds_epilog(void)
|
||||
*bounds_ptr = 0;
|
||||
|
||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
func_bound_offset, PTR_SIZE);
|
||||
|
||||
/* generate bound local allocation */
|
||||
if (offset_modified) {
|
||||
|
@ -3,6 +3,7 @@
|
||||
#define EM_TCC_TARGET EM_AARCH64
|
||||
|
||||
#define R_DATA_32 R_AARCH64_ABS32
|
||||
#define R_DATA_32U R_AARCH64_ABS32
|
||||
#define R_DATA_PTR R_AARCH64_ABS64
|
||||
#define R_JMP_SLOT R_AARCH64_JUMP_SLOT
|
||||
#define R_GLOB_DAT R_AARCH64_GLOB_DAT
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
/* relocation type for 32 bit data relocation */
|
||||
#define R_DATA_32 R_C60_32
|
||||
#define R_DATA_32U R_C60_32
|
||||
#define R_DATA_PTR R_C60_32
|
||||
#define R_JMP_SLOT R_C60_JMP_SLOT
|
||||
#define R_GLOB_DAT R_C60_GLOB_DAT
|
||||
|
5
configure
vendored
5
configure
vendored
@ -51,6 +51,7 @@ ar_set=
|
||||
darwin=
|
||||
cpu=
|
||||
cpuver=
|
||||
dwarf=
|
||||
|
||||
# OS specific
|
||||
cpu_sys=`uname -m`
|
||||
@ -136,6 +137,8 @@ for opt do
|
||||
;;
|
||||
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2-`
|
||||
;;
|
||||
--dwarf=*) dwarf=`echo $opt | cut -d '=' -f 2-`
|
||||
;;
|
||||
--enable-cross) confvars="$confvars cross"
|
||||
;;
|
||||
--disable-static) confvars="$confvars static=no"
|
||||
@ -328,6 +331,7 @@ Advanced options (experts only):
|
||||
--config-backtrace=no disable stack backtraces (with -run or -bt)
|
||||
--config-bcheck=no disable bounds checker (-b)
|
||||
--config-predefs=no do not compile tccdefs.h, instead just include
|
||||
--dwarf=x Use dwarf debug info instead of stabs (x=2..5)
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
@ -493,6 +497,7 @@ print_mak CONFIG_TCC_ELFINTERP "$tcc_elfinterp"
|
||||
print_mak CONFIG_LDDIR "$tcc_lddir"
|
||||
print_mak CONFIG_TRIPLET "$triplet"
|
||||
print_mak TCC_CPU_VERSION "$cpuver" num
|
||||
print_mak CONFIG_DWARF "$dwarf"
|
||||
|
||||
echo "ARCH=$cpu" >> config.mak
|
||||
echo "TARGETOS=$targetos" >> config.mak
|
||||
|
@ -1071,7 +1071,7 @@ static void gen_bounds_epilog(void)
|
||||
*bounds_ptr = 0;
|
||||
|
||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
func_bound_offset, PTR_SIZE);
|
||||
|
||||
/* generate bound local allocation */
|
||||
if (offset_modified) {
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
/* relocation type for 32 bit data relocation */
|
||||
#define R_DATA_32 R_386_32
|
||||
#define R_DATA_32U R_386_32
|
||||
#define R_DATA_PTR R_386_32
|
||||
#define R_JMP_SLOT R_386_JMP_SLOT
|
||||
#define R_GLOB_DAT R_386_GLOB_DAT
|
||||
|
@ -27,7 +27,7 @@ arm-libtcc1-usegcc ?= no
|
||||
ifeq "$($(T)-libtcc1-usegcc)" "yes"
|
||||
XCC = $(CC)
|
||||
XAR = $(AR)
|
||||
XFLAGS = $(CFLAGS) -fPIC -gstabs -fno-omit-frame-pointer -Wno-unused-function -Wno-unused-variable
|
||||
XFLAGS = $(CFLAGS) -fPIC -gdwarf -fno-omit-frame-pointer -Wno-unused-function -Wno-unused-variable
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_backtrace),no)
|
||||
|
@ -18,6 +18,10 @@ void __bt_init(rt_context *p, int num_callers)
|
||||
__attribute__((weak)) void __bound_init(void*, int);
|
||||
struct rt_context *rc = &g_rtctxt;
|
||||
//fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr);
|
||||
/* call __bound_init here due to redirection of sigaction */
|
||||
/* needed to add global symbols */
|
||||
if (__bound_init && p->bounds_start)
|
||||
__bound_init(p->bounds_start, -1);
|
||||
if (num_callers) {
|
||||
memcpy(rc, p, offsetof(rt_context, next));
|
||||
rc->num_callers = num_callers - 1;
|
||||
|
19
libtcc.c
19
libtcc.c
@ -1722,6 +1722,12 @@ static void args_parser_listfile(TCCState *s,
|
||||
*pargc = s->argc = argc, *pargv = s->argv = argv;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DWARF
|
||||
#define DWARF_VERSION atoi(CONFIG_DWARF)
|
||||
#else
|
||||
#define DWARF_VERSION 0
|
||||
#endif
|
||||
|
||||
PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
|
||||
{
|
||||
TCCState *s1 = s;
|
||||
@ -1819,6 +1825,7 @@ reparse:
|
||||
s->rt_num_callers = atoi(optarg);
|
||||
s->do_backtrace = 1;
|
||||
s->do_debug = 1;
|
||||
s->dwarf = DWARF_VERSION;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
@ -1826,16 +1833,22 @@ reparse:
|
||||
s->do_bounds_check = 1;
|
||||
s->do_backtrace = 1;
|
||||
s->do_debug = 1;
|
||||
s->dwarf = DWARF_VERSION;
|
||||
break;
|
||||
#endif
|
||||
case TCC_OPTION_g:
|
||||
/* Use "-g" as alias for "-g1". Use "-g0" to disable debug */
|
||||
/* Other common used values: "-g0", "-g1", "-g2" and "-g3" */
|
||||
/* no failure with unsupported options */
|
||||
if (isnum(*optarg))
|
||||
s->do_debug = 1;
|
||||
s->dwarf = DWARF_VERSION;
|
||||
if (*optarg == 'd') {
|
||||
s->dwarf = 5;
|
||||
if (!strncmp(optarg,"dwarf-",6))
|
||||
s->dwarf = atoi(optarg + 6);
|
||||
}
|
||||
else if (isnum(*optarg))
|
||||
s->do_debug = atoi(optarg);
|
||||
else
|
||||
s->do_debug = 1;
|
||||
break;
|
||||
case TCC_OPTION_c:
|
||||
x = TCC_OUTPUT_OBJ;
|
||||
|
@ -471,7 +471,7 @@ static void gen_bounds_epilog(void)
|
||||
*bounds_ptr = 0;
|
||||
|
||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
func_bound_offset, PTR_SIZE);
|
||||
|
||||
label.type.t = VT_VOID | VT_STATIC;
|
||||
/* generate bound local allocation */
|
||||
|
@ -3,6 +3,7 @@
|
||||
#define EM_TCC_TARGET EM_RISCV
|
||||
|
||||
#define R_DATA_32 R_RISCV_32
|
||||
#define R_DATA_32U R_RISCV_32
|
||||
#define R_DATA_PTR R_RISCV_64
|
||||
#define R_JMP_SLOT R_RISCV_JUMP_SLOT
|
||||
#define R_GLOB_DAT R_RISCV_64
|
||||
|
@ -349,12 +349,15 @@ Turn on/off linking of all objects in archives.
|
||||
Debugger options:
|
||||
|
||||
@table @option
|
||||
@item -g
|
||||
Generate run time debug information so that you get clear run time
|
||||
@item -g[x]
|
||||
Generate run time stab debug information so that you get clear run time
|
||||
error messages: @code{ test.c:68: in function 'test5()': dereferencing
|
||||
invalid pointer} instead of the laconic @code{Segmentation
|
||||
fault}.
|
||||
|
||||
@item -gdwarf[-x]
|
||||
Generate run time dwarf debug information instead of stab debug information.
|
||||
|
||||
@item -b
|
||||
Generate additional support code to check memory allocations and array/pointer
|
||||
bounds (@pxref{Bounds}). @option{-g} is implied.
|
||||
|
3
tcc.c
3
tcc.c
@ -58,7 +58,8 @@ static const char help[] =
|
||||
" -soname set name for shared library to be used at runtime\n"
|
||||
" -Wl,-opt[=val] set linker option (see tcc -hh)\n"
|
||||
"Debugger options:\n"
|
||||
" -g generate runtime debug info\n"
|
||||
" -g[x] generate stab runtime debug info\n"
|
||||
" -gdwarf[-x] generate dwarf runtime debug info\n"
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
" -b compile with built-in memory and bounds checker (implies -g)\n"
|
||||
#endif
|
||||
|
14
tcc.h
14
tcc.h
@ -368,6 +368,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
||||
#include "libtcc.h"
|
||||
#include "elf.h"
|
||||
#include "stab.h"
|
||||
#include "dwarf.h"
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
@ -792,6 +793,7 @@ struct TCCState {
|
||||
|
||||
/* compile with debug symbol (and use them if error during execution) */
|
||||
unsigned char do_debug;
|
||||
unsigned char dwarf;
|
||||
unsigned char do_backtrace;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* compile with built-in memory and bounds checker */
|
||||
@ -922,6 +924,12 @@ struct TCCState {
|
||||
Section *symtab_section;
|
||||
/* debug sections */
|
||||
Section *stab_section;
|
||||
Section *dwarf_info_section;
|
||||
Section *dwarf_abbrev_section;
|
||||
Section *dwarf_line_section;
|
||||
Section *dwarf_aranges_section;
|
||||
Section *dwarf_str_section;
|
||||
Section *dwarf_line_str_section;
|
||||
/* Is there a new undefined sym since last new_undef_sym() */
|
||||
int new_undef_sym;
|
||||
|
||||
@ -1822,6 +1830,12 @@ ST_FUNC void post_sem(TCCSem *p);
|
||||
#define symtab_section TCC_STATE_VAR(symtab_section)
|
||||
#define stab_section TCC_STATE_VAR(stab_section)
|
||||
#define stabstr_section stab_section->link
|
||||
#define dwarf_info_section TCC_STATE_VAR(dwarf_info_section)
|
||||
#define dwarf_abbrev_section TCC_STATE_VAR(dwarf_abbrev_section)
|
||||
#define dwarf_line_section TCC_STATE_VAR(dwarf_line_section)
|
||||
#define dwarf_aranges_section TCC_STATE_VAR(dwarf_aranges_section)
|
||||
#define dwarf_str_section TCC_STATE_VAR(dwarf_str_section)
|
||||
#define dwarf_line_str_section TCC_STATE_VAR(dwarf_line_str_section)
|
||||
#define gnu_ext TCC_STATE_VAR(gnu_ext)
|
||||
#define tcc_error_noabort TCC_SET_STATE(_tcc_error_noabort)
|
||||
#define tcc_error TCC_SET_STATE(_tcc_error)
|
||||
|
80
tccelf.c
80
tccelf.c
@ -47,6 +47,8 @@ struct sym_version {
|
||||
/* section is dynsymtab_section */
|
||||
#define SHF_DYNSYM 0x40000000
|
||||
|
||||
#define DWARF_DEBUG(s) (!strncmp((s), ".debug_", sizeof(".debug_")-1))
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
ST_FUNC void tccelf_new(TCCState *s)
|
||||
@ -102,12 +104,39 @@ ST_FUNC void tccelf_stab_new(TCCState *s)
|
||||
if (s->do_backtrace && s->output_type != TCC_OUTPUT_MEMORY)
|
||||
shf = SHF_ALLOC | SHF_WRITE; // SHF_WRITE needed for musl/SELINUX
|
||||
#endif
|
||||
stab_section = new_section(s, ".stab", SHT_PROGBITS, shf);
|
||||
stab_section->sh_entsize = sizeof(Stab_Sym);
|
||||
stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value;
|
||||
stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, shf);
|
||||
/* put first entry */
|
||||
put_stabs(s, "", 0, 0, 0, 0);
|
||||
if (s->dwarf) {
|
||||
dwarf_info_section =
|
||||
new_section(s, ".debug_info", SHT_PROGBITS, shf);
|
||||
dwarf_abbrev_section =
|
||||
new_section(s, ".debug_abbrev", SHT_PROGBITS, shf);
|
||||
dwarf_line_section =
|
||||
new_section(s, ".debug_line", SHT_PROGBITS, shf);
|
||||
dwarf_aranges_section =
|
||||
new_section(s, ".debug_aranges", SHT_PROGBITS, shf);
|
||||
shf |= SHF_MERGE | SHF_STRINGS;
|
||||
dwarf_str_section =
|
||||
new_section(s, ".debug_str", SHT_PROGBITS, shf);
|
||||
dwarf_str_section->sh_entsize = 1;
|
||||
dwarf_info_section->sh_addralign =
|
||||
dwarf_abbrev_section->sh_addralign =
|
||||
dwarf_line_section->sh_addralign =
|
||||
dwarf_aranges_section->sh_addralign =
|
||||
dwarf_str_section->sh_addralign = 1;
|
||||
if (s1->dwarf >= 5) {
|
||||
dwarf_line_str_section =
|
||||
new_section(s, ".debug_line_str", SHT_PROGBITS, shf);
|
||||
dwarf_line_str_section->sh_entsize = 1;
|
||||
dwarf_line_str_section->sh_addralign = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
stab_section = new_section(s, ".stab", SHT_PROGBITS, shf);
|
||||
stab_section->sh_entsize = sizeof(Stab_Sym);
|
||||
stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value;
|
||||
stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, shf);
|
||||
/* put first entry */
|
||||
put_stabs(s, "", 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_section(Section *s)
|
||||
@ -944,7 +973,10 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
|
||||
sym->st_value = 0;
|
||||
else
|
||||
tcc_error_noabort("undefined symbol '%s'", name);
|
||||
} else if (sh_num < SHN_LORESERVE) {
|
||||
} else if (sh_num < SHN_LORESERVE &&
|
||||
/* Debug dwarf relocations must be relative to start section.
|
||||
This only happens when backtrace is used. */
|
||||
(sym->st_name || !DWARF_DEBUG(s1->sections[sym->st_shndx]->name))) {
|
||||
/* add section base */
|
||||
sym->st_value += s1->sections[sym->st_shndx]->sh_addr;
|
||||
}
|
||||
@ -1330,7 +1362,7 @@ ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t
|
||||
if (sec && offs == -1)
|
||||
offs = sec->data_offset;
|
||||
return set_elf_sym(symtab_section, offs, 0,
|
||||
ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name);
|
||||
ELFW(ST_INFO)(name && !strstr(name, "__dwarf") ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name);
|
||||
}
|
||||
|
||||
static void add_init_array_defines(TCCState *s1, const char *section_name)
|
||||
@ -1395,10 +1427,10 @@ static void set_local_sym(TCCState *s1, const char *name, Section *s, int offset
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
static void put_ptr(TCCState *s1, Section *s, int offs)
|
||||
static void put_ptr(TCCState *s1, Section *s, int offs, const char *name)
|
||||
{
|
||||
int c;
|
||||
c = set_global_sym(s1, NULL, s, offs);
|
||||
c = set_global_sym(s1, name, s, offs);
|
||||
s = data_section;
|
||||
put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c);
|
||||
section_ptr_add(s, PTR_SIZE);
|
||||
@ -1415,16 +1447,29 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
|
||||
section_ptr_add(s, -s->data_offset & (PTR_SIZE - 1));
|
||||
o = s->data_offset;
|
||||
/* create (part of) a struct rt_context (see tccrun.c) */
|
||||
put_ptr(s1, stab_section, 0);
|
||||
put_ptr(s1, stab_section, -1);
|
||||
put_ptr(s1, stab_section->link, 0);
|
||||
if (s1->dwarf) {
|
||||
put_ptr(s1, dwarf_line_section, 0, "__dwarf_line");
|
||||
put_ptr(s1, dwarf_line_section, -1, "__dwarf_line_end");
|
||||
if (s1->dwarf >= 5)
|
||||
put_ptr(s1, dwarf_line_str_section, 0, "__dwarf_line_str");
|
||||
else
|
||||
put_ptr(s1, dwarf_str_section, 0, "__dwarf_str");
|
||||
put_ptr(s1, text_section, 0, "__dwarf_text");
|
||||
}
|
||||
else {
|
||||
put_ptr(s1, stab_section, 0, NULL);
|
||||
put_ptr(s1, stab_section, -1, NULL);
|
||||
put_ptr(s1, stab_section->link, 0, NULL);
|
||||
section_ptr_add(s, PTR_SIZE);
|
||||
}
|
||||
/* skip esym_start/esym_end/elf_str (not loaded) */
|
||||
section_ptr_add(s, 3 * PTR_SIZE);
|
||||
/* prog_base : local nameless symbol with offset 0 at SHN_ABS */
|
||||
put_ptr(s1, NULL, 0);
|
||||
put_ptr(s1, NULL, 0, NULL);
|
||||
n = 2 * PTR_SIZE;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (s1->do_bounds_check) {
|
||||
put_ptr(s1, bounds_section, 0);
|
||||
put_ptr(s1, bounds_section, 0, NULL);
|
||||
n -= PTR_SIZE;
|
||||
}
|
||||
#endif
|
||||
@ -1849,6 +1894,8 @@ static int set_sec_sizes(TCCState *s1)
|
||||
/* when generating a DLL, we include relocations but
|
||||
we may patch them */
|
||||
if (file_type == TCC_OUTPUT_DLL
|
||||
/* Do not include dwarf relocatable sections. */
|
||||
&& !DWARF_DEBUG(s1->sections[s->sh_info]->name)
|
||||
&& (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC)) {
|
||||
int count = prepare_dynamic_rel(s1, s);
|
||||
if (count) {
|
||||
@ -2963,8 +3010,7 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
|
||||
strcmp(strsec + sh->sh_name, ".stabstr")
|
||||
)
|
||||
continue;
|
||||
if (seencompressed
|
||||
&& !strncmp(strsec + sh->sh_name, ".debug_", sizeof(".debug_")-1))
|
||||
if (seencompressed && DWARF_DEBUG(strsec + sh->sh_name))
|
||||
continue;
|
||||
|
||||
sh = &shdr[i];
|
||||
|
363
tccrun.c
363
tccrun.c
@ -27,8 +27,16 @@
|
||||
typedef struct rt_context
|
||||
{
|
||||
/* --> tccelf.c:tcc_add_btstub wants those below in that order: */
|
||||
Stab_Sym *stab_sym, *stab_sym_end;
|
||||
char *stab_str;
|
||||
union {
|
||||
struct {
|
||||
Stab_Sym *stab_sym, *stab_sym_end;
|
||||
char *stab_str;
|
||||
};
|
||||
struct {
|
||||
unsigned char *dwarf_line, *dwarf_line_end, *dwarf_line_str;
|
||||
addr_t dwarf_text;
|
||||
};
|
||||
};
|
||||
ElfW(Sym) *esym_start, *esym_end;
|
||||
char *elf_str;
|
||||
addr_t prog_base;
|
||||
@ -169,9 +177,18 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
memset(rc, 0, sizeof *rc);
|
||||
if (s1->do_debug) {
|
||||
void *p;
|
||||
rc->stab_sym = (Stab_Sym *)stab_section->data;
|
||||
rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
|
||||
rc->stab_str = (char *)stab_section->link->data;
|
||||
if (s1->dwarf) {
|
||||
rc->dwarf_line = dwarf_line_section->data;
|
||||
rc->dwarf_line_end = dwarf_line_section->data + dwarf_line_section->data_offset;
|
||||
rc->dwarf_line_str = dwarf_line_str_section->data;
|
||||
rc->dwarf_text = text_section->sh_addr;
|
||||
}
|
||||
else {
|
||||
rc->stab_sym = (Stab_Sym *)stab_section->data;
|
||||
rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
|
||||
rc->stab_str = (char *)stab_section->link->data;
|
||||
rc->dwarf_text = 0;
|
||||
}
|
||||
rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
|
||||
rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
|
||||
rc->elf_str = (char *)symtab_section->link->data;
|
||||
@ -571,6 +588,337 @@ found:
|
||||
return func_addr;
|
||||
}
|
||||
|
||||
#define MAX_128 ((8 * sizeof (long long) + 6) / 7)
|
||||
|
||||
#define DW_GETC(s,e) ((s) < (e) ? *(s)++ : 0)
|
||||
|
||||
#define DIR_TABLE_SIZE (64)
|
||||
#define FILE_TABLE_SIZE (256)
|
||||
|
||||
static unsigned long long
|
||||
dwarf_read_uleb128(unsigned char **ln, unsigned char *end)
|
||||
{
|
||||
unsigned char *cp = *ln;
|
||||
unsigned long long retval = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_128; i++) {
|
||||
unsigned long long byte = DW_GETC(cp, end);
|
||||
|
||||
retval |= (byte & 0x7f) << (i * 7);
|
||||
if ((byte & 0x80) == 0)
|
||||
break;
|
||||
}
|
||||
*ln = cp;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static long long
|
||||
dwarf_read_sleb128(unsigned char **ln, unsigned char *end)
|
||||
{
|
||||
unsigned char *cp = *ln;
|
||||
long long retval = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_128; i++) {
|
||||
unsigned long long byte = DW_GETC(cp, end);
|
||||
|
||||
retval |= (byte & 0x7f) << (i * 7);
|
||||
if ((byte & 0x80) == 0) {
|
||||
if ((byte & 0x40) && (i + 1) * 7 < 64)
|
||||
retval |= -1LL << ((i + 1) * 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*ln = cp;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static unsigned int dwarf_read_32(unsigned char **ln, unsigned char *end)
|
||||
{
|
||||
unsigned char *cp = *ln;
|
||||
unsigned int retval = 0;
|
||||
|
||||
if ((cp + 4) < end) {
|
||||
retval = read32le(cp);
|
||||
cp += 4;
|
||||
}
|
||||
*ln = cp;
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if PTR_SIZE == 8
|
||||
static unsigned long long dwarf_read_64(unsigned char **ln, unsigned char *end)
|
||||
{
|
||||
unsigned char *cp = *ln;
|
||||
unsigned long long retval = 0;
|
||||
|
||||
if ((cp + 8) < end) {
|
||||
retval = read64le(cp);
|
||||
cp += 8;
|
||||
}
|
||||
*ln = cp;
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
|
||||
const char *msg, const char *skip)
|
||||
{
|
||||
unsigned char *ln;
|
||||
unsigned char *cp;
|
||||
unsigned char *end;
|
||||
unsigned int size;
|
||||
unsigned char version;
|
||||
unsigned int min_insn_length;
|
||||
unsigned int max_ops_per_insn;
|
||||
int line_base;
|
||||
unsigned int line_range;
|
||||
unsigned int opcode_base;
|
||||
unsigned int opindex;
|
||||
unsigned int col;
|
||||
unsigned int i;
|
||||
unsigned int len;
|
||||
unsigned int dir_size;
|
||||
#if 0
|
||||
char *dirs[DIR_TABLE_SIZE];
|
||||
#endif
|
||||
unsigned int filename_size;
|
||||
struct dwarf_filename_struct {
|
||||
unsigned int dir_entry;
|
||||
char *name;
|
||||
} filename_table[FILE_TABLE_SIZE];
|
||||
addr_t last_pc;
|
||||
addr_t pc;
|
||||
addr_t func_addr;
|
||||
int line;
|
||||
char *filename;
|
||||
char *function;
|
||||
ElfW(Sym) *esym;
|
||||
|
||||
next:
|
||||
ln = rc->dwarf_line;
|
||||
while (ln < rc->dwarf_line_end) {
|
||||
dir_size = 0;
|
||||
filename_size = 0;
|
||||
last_pc = 0;
|
||||
pc = 0;
|
||||
func_addr = -1;
|
||||
line = 1;
|
||||
filename = NULL;
|
||||
function = NULL;
|
||||
size = dwarf_read_32(&ln, rc->dwarf_line_end);
|
||||
end = ln + size;
|
||||
version = DW_GETC(ln, end);
|
||||
version += DW_GETC(ln, end) << 8;
|
||||
if (version >= 5)
|
||||
ln += 6; // address size, segment selector, prologue Length
|
||||
else
|
||||
ln += 4; // prologue Length
|
||||
min_insn_length = DW_GETC(ln, end);
|
||||
if (version >= 4)
|
||||
max_ops_per_insn = DW_GETC(ln, end);
|
||||
else
|
||||
max_ops_per_insn = 1;
|
||||
ln++; // Initial value of 'is_stmt'
|
||||
line_base = DW_GETC(ln, end);
|
||||
line_base |= line_base >= 0x80 ? ~0xff : 0;
|
||||
line_range = DW_GETC(ln, end);
|
||||
opcode_base = DW_GETC(ln, end);
|
||||
opindex = 0;
|
||||
ln += 12;
|
||||
if (version >= 5) {
|
||||
col = DW_GETC(ln, end);
|
||||
for (i = 0; i < col * 2; i++)
|
||||
dwarf_read_uleb128(&ln, end);
|
||||
dir_size = dwarf_read_uleb128(&ln, end);
|
||||
for (i = 0; i < dir_size; i++)
|
||||
#if 0
|
||||
if (i < DIR_TABLE_SIZE)
|
||||
dirs[i] = (char *)rc->dwarf_line_str + dwarf_read_32(&ln, end);
|
||||
else
|
||||
#endif
|
||||
dwarf_read_32(&ln, end);
|
||||
col = DW_GETC(ln, end);
|
||||
for (i = 0; i < col * 2; i++)
|
||||
dwarf_read_uleb128(&ln, end);
|
||||
filename_size = dwarf_read_uleb128(&ln, end);
|
||||
for (i = 0; i < filename_size; i++)
|
||||
if (i < FILE_TABLE_SIZE) {
|
||||
filename_table[i].name = (char *)rc->dwarf_line_str + dwarf_read_32(&ln, end);
|
||||
filename_table[i].dir_entry = dwarf_read_uleb128(&ln, end);
|
||||
}
|
||||
else {
|
||||
dwarf_read_32(&ln, end);
|
||||
dwarf_read_uleb128(&ln, end);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while ((i = DW_GETC(ln, end))) {
|
||||
#if 0
|
||||
if (++dir_size < DIR_TABLE_SIZE)
|
||||
dirs[dir_size - 1] = (char *)ln - 1;
|
||||
#endif
|
||||
while (DW_GETC(ln, end)) {}
|
||||
}
|
||||
while ((i = DW_GETC(ln, end))) {
|
||||
if (++filename_size < FILE_TABLE_SIZE) {
|
||||
filename_table[filename_size - 1].name = (char *)ln - 1;
|
||||
while (DW_GETC(ln, end)) {}
|
||||
filename_table[filename_size - 1].dir_entry =
|
||||
dwarf_read_uleb128(&ln, end);
|
||||
}
|
||||
else {
|
||||
while (DW_GETC(ln, end)) {}
|
||||
dwarf_read_uleb128(&ln, end);
|
||||
}
|
||||
dwarf_read_uleb128(&ln, end); // time
|
||||
dwarf_read_uleb128(&ln, end); // size
|
||||
}
|
||||
}
|
||||
while (ln < end) {
|
||||
last_pc = pc;
|
||||
switch (DW_GETC(ln, end)) {
|
||||
case 0:
|
||||
len = dwarf_read_uleb128(&ln, end);
|
||||
cp = ln;
|
||||
ln += len;
|
||||
if (len == 0)
|
||||
goto next_line;
|
||||
switch (DW_GETC(cp, end)) {
|
||||
case DW_LNE_end_sequence:
|
||||
goto next_line;
|
||||
case DW_LNE_set_address:
|
||||
#if PTR_SIZE == 4
|
||||
dwarf_read_32(&cp, end);
|
||||
#else
|
||||
dwarf_read_64(&cp, end);
|
||||
#endif
|
||||
pc = rc->dwarf_text;
|
||||
opindex = 0;
|
||||
break;
|
||||
case DW_LNE_define_file: /* deprecated */
|
||||
break;
|
||||
case DW_LNE_set_discriminator:
|
||||
dwarf_read_uleb128(&cp, end);
|
||||
break;
|
||||
case DW_LNE_hi_user - 1:
|
||||
function = (char *)cp;
|
||||
func_addr = pc;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DW_LNS_copy:
|
||||
break;
|
||||
case DW_LNS_advance_pc:
|
||||
if (max_ops_per_insn == 1)
|
||||
pc += dwarf_read_uleb128(&ln, end) * min_insn_length;
|
||||
else {
|
||||
unsigned long long off = dwarf_read_uleb128(&ln, end);
|
||||
|
||||
pc += (opindex + off) / max_ops_per_insn *
|
||||
min_insn_length;
|
||||
opindex = (opindex + off) % max_ops_per_insn;
|
||||
}
|
||||
i = 0;
|
||||
goto check_pc;
|
||||
case DW_LNS_advance_line:
|
||||
line += dwarf_read_sleb128(&ln, end);
|
||||
break;
|
||||
case DW_LNS_set_file:
|
||||
i = dwarf_read_uleb128(&ln, end);
|
||||
if (i < FILE_TABLE_SIZE && i < filename_size)
|
||||
filename = filename_table[i].name;
|
||||
break;
|
||||
case DW_LNS_set_column:
|
||||
dwarf_read_uleb128(&ln, end);
|
||||
break;
|
||||
case DW_LNS_negate_stmt:
|
||||
break;
|
||||
case DW_LNS_set_basic_block:
|
||||
break;
|
||||
case DW_LNS_const_add_pc:
|
||||
if (max_ops_per_insn == 1)
|
||||
pc += ((255 - opcode_base) / line_range) * min_insn_length;
|
||||
else {
|
||||
unsigned int off = (255 - opcode_base) / line_range;
|
||||
|
||||
pc += ((opindex + off) / max_ops_per_insn) *
|
||||
min_insn_length;
|
||||
opindex = (opindex + off) % max_ops_per_insn;
|
||||
}
|
||||
i = 0;
|
||||
goto check_pc;
|
||||
case DW_LNS_fixed_advance_pc:
|
||||
i = DW_GETC(ln, end);
|
||||
i += DW_GETC(ln, end) << 8;
|
||||
pc += i;
|
||||
opindex = 0;
|
||||
i = 0;
|
||||
goto check_pc;
|
||||
case DW_LNS_set_prologue_end:
|
||||
break;
|
||||
case DW_LNS_set_epilogue_begin:
|
||||
break;
|
||||
case DW_LNS_set_isa:
|
||||
dwarf_read_uleb128(&ln, end);
|
||||
break;
|
||||
default:
|
||||
i = ln[-1];
|
||||
if (max_ops_per_insn == 1)
|
||||
pc += ((i - opcode_base) / line_range) * min_insn_length;
|
||||
else {
|
||||
pc += (opindex + (i - opcode_base) / line_range) /
|
||||
max_ops_per_insn * min_insn_length;
|
||||
opindex = (opindex + (i - opcode_base) / line_range) %
|
||||
max_ops_per_insn;
|
||||
}
|
||||
i = (int)((i - opcode_base) % line_range) + line_base;
|
||||
check_pc:
|
||||
if (pc >= wanted_pc && wanted_pc >= last_pc)
|
||||
goto found;
|
||||
line += i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
next_line:
|
||||
ln = end;
|
||||
}
|
||||
|
||||
filename = NULL;
|
||||
function = NULL;
|
||||
func_addr = -1;
|
||||
|
||||
/* we try symtab symbols (no line number info) */
|
||||
for (esym = rc->esym_start + 1; esym < rc->esym_end; ++esym) {
|
||||
int type = ELFW(ST_TYPE)(esym->st_info);
|
||||
if (type == STT_FUNC || type == STT_GNU_IFUNC) {
|
||||
if (wanted_pc >= esym->st_value &&
|
||||
wanted_pc < esym->st_value + esym->st_size) {
|
||||
function = rc->elf_str + esym->st_name;
|
||||
func_addr = esym->st_value;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((rc = rc->next))
|
||||
goto next;
|
||||
|
||||
found:
|
||||
if (filename) {
|
||||
if (skip[0] && strstr(filename, skip))
|
||||
return (addr_t)-1;
|
||||
rt_printf("%s:%d: ", filename, line);
|
||||
}
|
||||
else
|
||||
rt_printf("0x%08llx : ", (long long)wanted_pc);
|
||||
rt_printf("%s %s", msg, function ? function : "???");
|
||||
return (addr_t)func_addr;
|
||||
}
|
||||
|
||||
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level);
|
||||
|
||||
static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
|
||||
@ -603,7 +951,10 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
|
||||
ret = rt_get_caller_pc(&pc, rc, i);
|
||||
a = "%s";
|
||||
if (ret != -1) {
|
||||
pc = rt_printline(rc, pc, level ? "by" : "at", skip);
|
||||
if ((addr_t)rc->dwarf_text)
|
||||
pc = rt_printline_dwarf(rc, pc, level ? "by" : "at", skip);
|
||||
else
|
||||
pc = rt_printline(rc, pc, level ? "by" : "at", skip);
|
||||
if (pc == (addr_t)-1)
|
||||
continue;
|
||||
a = ": %s";
|
||||
|
13
tests/tests2/126_bound_global.c
Normal file
13
tests/tests2/126_bound_global.c
Normal file
@ -0,0 +1,13 @@
|
||||
/* test bound checking code without -run */
|
||||
|
||||
int arr[10];
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= sizeof(arr)/sizeof(arr[0]); i++)
|
||||
arr[i] = 0;
|
||||
return 0;
|
||||
}
|
2
tests/tests2/126_bound_global.expect
Normal file
2
tests/tests2/126_bound_global.expect
Normal file
@ -0,0 +1,2 @@
|
||||
126_bound_global.c:11: at main: BCHECK: ........ is outside of the region
|
||||
126_bound_global.c:11: at main: RUNTIME ERROR: invalid memory access
|
@ -58,6 +58,9 @@ ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS)))
|
||||
SKIP += 114_bound_signal.test # libc problem signal/fork
|
||||
SKIP += 116_bound_setjmp2.test # No TLS_FUNC/TLS_VAR in bcheck.c
|
||||
endif
|
||||
ifneq (,$(filter Darwin,$(TARGETOS)))
|
||||
SKIP += 126_bound_global.test # bt-exe.c problem on apple
|
||||
endif
|
||||
|
||||
# Some tests might need arguments
|
||||
ARGS =
|
||||
@ -100,7 +103,7 @@ GEN-ALWAYS =
|
||||
108_constructor.test: NORUN = true
|
||||
|
||||
112_backtrace.test: FLAGS += -dt -b
|
||||
112_backtrace.test 113_btdll.test: FILTER += \
|
||||
112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \
|
||||
-e 's;[0-9A-Fa-fx]\{5,\};........;g' \
|
||||
-e 's;0x[0-9A-Fa-f]\{1,\};0x?;g'
|
||||
|
||||
@ -122,6 +125,8 @@ ifneq ($(CONFIG_bcheck),no)
|
||||
endif
|
||||
125_atomic_misc.test: FLAGS += -dt
|
||||
124_atomic_counter.test: FLAGS += -pthread
|
||||
126_bound_global.test: FLAGS += -b
|
||||
126_bound_global.test: NORUN = true
|
||||
|
||||
# Filter source directory in warnings/errors (out-of-tree builds)
|
||||
FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'
|
||||
|
@ -701,7 +701,7 @@ static void gen_bounds_epilog(void)
|
||||
*bounds_ptr = 0;
|
||||
|
||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
func_bound_offset, PTR_SIZE);
|
||||
|
||||
/* generate bound local allocation */
|
||||
if (offset_modified) {
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
/* relocation type for 32 bit data relocation */
|
||||
#define R_DATA_32 R_X86_64_32S
|
||||
#define R_DATA_32U R_X86_64_32
|
||||
#define R_DATA_PTR R_X86_64_64
|
||||
#define R_JMP_SLOT R_X86_64_JUMP_SLOT
|
||||
#define R_GLOB_DAT R_X86_64_GLOB_DAT
|
||||
|
Loading…
Reference in New Issue
Block a user