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:
herman ten brugge 2022-05-05 09:10:37 +02:00
parent d3e940c71c
commit 2f2708a769
26 changed files with 2754 additions and 144 deletions

1
.gitignore vendored
View File

@ -24,6 +24,7 @@ config*.h
config*.mak
config.texi
conftest*
c2str
tags
TAGS
tcc.1

View File

@ -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) {

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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
View File

@ -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

1046
dwarf.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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) {

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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
View File

@ -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
View File

@ -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)

View File

@ -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];

1316
tccgen.c

File diff suppressed because it is too large Load Diff

363
tccrun.c
View File

@ -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";

View 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;
}

View 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

View File

@ -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'

View File

@ -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) {

View File

@ -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