Fix bound checking dlcose problem

The main problem is that an application called dlclose and then
had a bound checking problem. The list of dll's in tccrun was
not updated an caused a crash.
Also fixed some minor other things.

tccdbg.c:
- Allow filenames like ../file.c
- Rewrite DWARF_ABBREV_MEMBER_BF/DWARF_ABBREV_MEMBER a bit

tccelf.c:
- Add call to __bt_exit. This solves problem when dlclose is called

tccrun.c:
- Rewrite rt_printline_dwarf a litlle to use opcode_length correctly
- Do not stop at DW_LNE_end_sequence
- Fix DW_LNE_set_address again. Works now in *bsd.

lib/bt-exe.c lib/bt-dll.c:
- Add __bt_exit/__bound_exit_dll

lib/bcheck.c:
- Add __bound_exit_dll
This commit is contained in:
herman ten brugge 2022-05-19 07:40:14 +02:00
parent 4c82b00342
commit aaec564a82
6 changed files with 192 additions and 149 deletions

View File

@ -270,6 +270,7 @@ DLL_EXPORT void FASTCALL __bound_local_delete(void *p1);
void __bound_init(size_t *, int);
void __bound_main_arg(int argc, char **argv, char **envp);
void __bound_exit(void);
void __bound_exit_dll(size_t *);
#if !defined(_WIN32)
void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd,
off_t offset);
@ -1255,6 +1256,25 @@ void __attribute__((destructor)) __bound_exit(void)
}
}
void __bound_exit_dll(size_t *p)
{
dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
if (p) {
while (p[0] != 0) {
tree = splay_delete(p[0], tree);
#if BOUND_DEBUG
if (print_calls) {
dprintf(stderr, "%s, %s(): remove static var %p 0x%lx\n",
__FILE__, __FUNCTION__,
(void *) p[0], (unsigned long) p[1]);
}
#endif
p += 2;
}
}
}
#if HAVE_PTHREAD_CREATE
typedef struct {
void *(*start_routine) (void *);

View File

@ -6,6 +6,8 @@
#define REDIR_ALL \
REDIR(__bt_init) \
REDIR(__bt_exit) \
REDIR(__bound_exit_dll) \
REDIR(tcc_backtrace) \
\
REDIR(__bound_ptr_add) \

View File

@ -30,11 +30,27 @@ void __bt_init(rt_context *p, int num_callers)
__rt_error = _rt_error;
set_exception_handler();
} else {
p->num_callers = -1;
p->next = rc->next, rc->next = p;
}
}
__declspec(dllexport)
void __bt_exit(rt_context *p)
{
__attribute__((weak)) void __bound_exit_dll(void*);
struct rt_context *rc = &g_rtctxt;
if (__bound_exit_dll && p->bounds_start)
__bound_exit_dll(p->bounds_start);
while (rc) {
if (rc->next == p) {
rc->next = rc->next->next;
break;
}
rc = rc->next;
}
}
/* copy a string and truncate it. */
ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s)
{

View File

@ -541,7 +541,7 @@ static void dwarf_file(TCCState *s1)
filename = strrchr(file->filename, '/');
if (filename == NULL) {
for (i = 1; i < dwarf_line.filename_size; i++)
for (i = 0; i < dwarf_line.filename_size; i++)
if (dwarf_line.filename_table[i].dir_entry == 0 &&
strcmp(dwarf_line.filename_table[i].name,
file->filename) == 0) {
@ -685,6 +685,7 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
if (s1->dwarf) {
int start_abbrev;
unsigned char *ptr;
char *undo;
/* dwarf_abbrev */
start_abbrev = dwarf_abbrev_section->data_offset;
@ -775,18 +776,32 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
dwarf_data1(dwarf_line_section, DWARF_OPCODE_BASE);
ptr = section_ptr_add(dwarf_line_section, sizeof(dwarf_line_opcodes));
memcpy(ptr, dwarf_line_opcodes, sizeof(dwarf_line_opcodes));
dwarf_line.dir_size = 1;
dwarf_line.dir_table = (char **) tcc_malloc(sizeof (char *));
undo = strrchr(filename, '/');
if (undo)
*undo = 0;
dwarf_line.dir_size = 1 + (undo != NULL);
dwarf_line.dir_table = (char **) tcc_malloc(sizeof (char *) *
dwarf_line.dir_size);
dwarf_line.dir_table[0] = tcc_strdup(buf);
/* line state machine starts with file 1 instead of 0 */
if (undo)
dwarf_line.dir_table[1] = tcc_strdup(filename);
dwarf_line.filename_size = 2;
dwarf_line.filename_table =
(struct dwarf_filename_struct *)
tcc_malloc(2*sizeof (struct dwarf_filename_struct));
dwarf_line.filename_table[0].dir_entry = 0;
dwarf_line.filename_table[0].name = tcc_strdup(filename);
dwarf_line.filename_table[1].dir_entry = 0;
dwarf_line.filename_table[1].name = tcc_strdup(filename);
if (undo) {
dwarf_line.filename_table[0].name = tcc_strdup(filename);
dwarf_line.filename_table[1].dir_entry = 1;
dwarf_line.filename_table[1].name = tcc_strdup(undo + 1);
*undo = '/';
dwarf_line.filename_table[0].name = tcc_strdup(filename);
}
else {
dwarf_line.filename_table[0].name = tcc_strdup(filename);
dwarf_line.filename_table[1].dir_entry = 0;
dwarf_line.filename_table[1].name = tcc_strdup(filename);
}
dwarf_line.line_size = dwarf_line.line_max_size = 0;
dwarf_line.line_data = NULL;
dwarf_line.cur_file = 1;
@ -1020,7 +1035,8 @@ ST_FUNC void tcc_debug_bincl(TCCState *s1)
}
if (strcmp(filename, "<command line>")) {
for (j = 0; j < dwarf_line.filename_size; j++)
if (strcmp (dwarf_line.filename_table[j].name, filename) == 0)
if (dwarf_line.filename_table[j].dir_entry == i &&
strcmp (dwarf_line.filename_table[j].name, filename) == 0)
break;
if (j == dwarf_line.filename_size) {
dwarf_line.filename_table =
@ -1428,32 +1444,25 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
i = 0;
while (e->next) {
e = e->next;
dwarf_data1(dwarf_info_section,
e->type.t & VT_BITFIELD ? DWARF_ABBREV_MEMBER_BF
: DWARF_ABBREV_MEMBER);
dwarf_strp(dwarf_info_section,
(e->v & ~SYM_FIELD) >= SYM_FIRST_ANOM
? "" : get_tok_str(e->v & ~SYM_FIELD, NULL));
dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file);
dwarf_uleb128(dwarf_info_section, file->line_num);
pos_type[i++] = dwarf_info_section->data_offset;
dwarf_data4(dwarf_info_section, 0);
if (e->type.t & VT_BITFIELD) {
int pos = e->c * 8 + BIT_POS(e->type.t);
int size = BIT_SIZE(e->type.t);
dwarf_data1(dwarf_info_section, DWARF_ABBREV_MEMBER_BF);
dwarf_strp(dwarf_info_section,
(e->v & ~SYM_FIELD) >= SYM_FIRST_ANOM
? "" : get_tok_str(e->v & ~SYM_FIELD, NULL));
dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file);
dwarf_uleb128(dwarf_info_section, file->line_num);
pos_type[i++] = dwarf_info_section->data_offset;
dwarf_data4(dwarf_info_section, 0);
dwarf_uleb128(dwarf_info_section, size);
dwarf_uleb128(dwarf_info_section, pos);
}
else {
dwarf_data1(dwarf_info_section, DWARF_ABBREV_MEMBER);
dwarf_strp(dwarf_info_section,
(e->v & ~SYM_FIELD) >= SYM_FIRST_ANOM
? "" : get_tok_str(e->v & ~SYM_FIELD, NULL));
dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file);
dwarf_uleb128(dwarf_info_section, file->line_num);
pos_type[i++] = dwarf_info_section->data_offset;
dwarf_data4(dwarf_info_section, 0);
else
dwarf_uleb128(dwarf_info_section, e->c);
}
}
dwarf_data1(dwarf_info_section, 0);
write32le(dwarf_info_section->data + pos_sib,
@ -1785,12 +1794,13 @@ ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym)
dwarf_info.func = sym;
dwarf_info.line = file->line_num;
if (s1->do_backtrace) {
int i;
int i, len;
dwarf_line_op(s1, 0); // extended
dwarf_uleb128_op(s1, strlen(funcname) + 2);
dwarf_line_op(s1, DW_LNE_hi_user - 1);
for (i = 0; i < strlen(funcname) + 1; i++)
len = strlen(funcname) + 1;
for (i = 0; i < len; i++)
dwarf_line_op(s1, funcname[i]);
}
}

View File

@ -1389,15 +1389,14 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
put_ptr(s1, dwarf_line_str_section, 0);
else
put_ptr(s1, dwarf_str_section, 0);
put_ptr(s1, text_section, 0);
}
else
{
put_ptr(s1, stab_section, 0);
put_ptr(s1, stab_section, -1);
put_ptr(s1, stab_section->link, 0);
section_ptr_add(s, PTR_SIZE);
}
*(addr_t *)section_ptr_add(s, PTR_SIZE) = s1->dwarf;
/* 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 */
@ -1412,7 +1411,7 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
section_ptr_add(s, n);
cstr_new(&cstr);
cstr_printf(&cstr,
"extern void __bt_init(),__bt_init_dll();"
"extern void __bt_init(),__bt_exit(),__bt_init_dll();"
"static void *__rt_info[];"
"__attribute__((constructor)) static void __bt_init_rt(){");
#ifdef TCC_TARGET_PE
@ -1425,6 +1424,10 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
#endif
cstr_printf(&cstr, "__bt_init(__rt_info,%d);}",
s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1);
/* In case dlcose is called by application */
cstr_printf(&cstr,
"__attribute__((destructor)) static void __bt_exit_rt(){"
"__bt_exit(__rt_info);}");
tcc_compile_string_no_debug(s1, cstr.data);
cstr_free(&cstr);
set_local_sym(s1, &"___rt_info"[!s1->leading_underscore], s, o);

226
tccrun.c
View File

@ -34,9 +34,9 @@ typedef struct rt_context
};
struct {
unsigned char *dwarf_line, *dwarf_line_end, *dwarf_line_str;
addr_t dwarf_text;
};
};
addr_t dwarf;
ElfW(Sym) *esym_start, *esym_end;
char *elf_str;
addr_t prog_base;
@ -182,15 +182,14 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
rc->dwarf_line_end = dwarf_line_section->data + dwarf_line_section->data_offset;
if (dwarf_line_str_section)
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->dwarf = s1->dwarf;
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;
@ -666,7 +665,9 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
unsigned char *ln;
unsigned char *cp;
unsigned char *end;
unsigned int size;
unsigned char *opcode_length;
unsigned long long size;
unsigned int length;
unsigned char version;
unsigned int min_insn_length;
unsigned int max_ops_per_insn;
@ -678,7 +679,7 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
unsigned int i;
unsigned int j;
unsigned int len;
unsigned int value;
unsigned long long value;
struct {
unsigned int type;
unsigned int form;
@ -695,13 +696,11 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
addr_t last_pc;
addr_t pc;
addr_t func_addr;
addr_t offset_dll;
int line;
char *filename;
char *function;
next:
offset_dll = 0;
ln = rc->dwarf_line;
while (ln < rc->dwarf_line_end) {
dir_size = 0;
@ -712,13 +711,18 @@ next:
line = 1;
filename = NULL;
function = NULL;
length = 4;
size = dwarf_read_4(ln, rc->dwarf_line_end);
if (size == 0xffffffffu) // dwarf 64
length = 8, size = dwarf_read_8(ln, rc->dwarf_line_end);
end = ln + size;
if (end < ln || end > rc->dwarf_line_end)
break;
version = dwarf_read_2(ln, end);
if (version >= 5)
ln += 6; // address size, segment selector, prologue Length
ln += length + 2; // address size, segment selector, prologue Length
else
ln += 4; // prologue Length
ln += length; // prologue Length
min_insn_length = dwarf_read_1(ln, end);
if (version >= 4)
max_ops_per_insn = dwarf_read_1(ln, end);
@ -729,8 +733,9 @@ next:
line_base |= line_base >= 0x80 ? ~0xff : 0;
line_range = dwarf_read_1(ln, end);
opcode_base = dwarf_read_1(ln, end);
opcode_length = ln;
ln += opcode_base - 1;
opindex = 0;
ln += 12;
if (version >= 5) {
col = dwarf_read_1(ln, end);
for (i = 0; i < col; i++) {
@ -744,11 +749,13 @@ next:
if (entry_format[j].form != DW_FORM_line_strp)
goto next_line;
#if 0
value = dwarf_read_4(ln, end);
value = length == 4 ? dwarf_read_4(ln, end)
: dwarf_read_8(ln, end);
if (i < DIR_TABLE_SIZE)
dirs[i] = (char *)rc->dwarf_line_str + value;
#else
dwarf_read_4(ln, end);
length == 4 ? dwarf_read_4(ln, end)
: dwarf_read_8(ln, end);
#endif
}
else
@ -766,7 +773,8 @@ next:
if (entry_format[j].type == DW_LNCT_path) {
if (entry_format[j].form != DW_FORM_line_strp)
goto next_line;
value = dwarf_read_4(ln, end);
value = length == 4 ? dwarf_read_4(ln, end)
: dwarf_read_8(ln, end);
if (i < FILE_TABLE_SIZE)
filename_table[i].name =
(char *)rc->dwarf_line_str + value;
@ -813,108 +821,8 @@ next:
filename = filename_table[0].name;
while (ln < end) {
last_pc = pc;
switch (dwarf_read_1(ln, end)) {
case 0:
len = dwarf_read_uleb128(&ln, end);
cp = ln;
ln += len;
if (len == 0)
goto next_line;
switch (dwarf_read_1(cp, end)) {
case DW_LNE_end_sequence:
goto next_line;
case DW_LNE_set_address:
#if PTR_SIZE == 4
pc = dwarf_read_4(cp, end);
#else
pc = dwarf_read_8(cp, end);
#endif
if (rc->num_callers < 0) {
/* dll */
if (!offset_dll)
offset_dll = pc;
pc = rc->dwarf_text + (pc - offset_dll);
}
opindex = 0;
break;
case DW_LNE_define_file: /* deprecated */
if (++filename_size < FILE_TABLE_SIZE) {
filename_table[filename_size - 1].name = (char *)ln - 1;
while (dwarf_read_1(ln, end)) {}
filename_table[filename_size - 1].dir_entry =
dwarf_read_uleb128(&ln, end);
}
else {
while (dwarf_read_1(ln, end)) {}
dwarf_read_uleb128(&ln, end);
}
dwarf_read_uleb128(&ln, end); // time
dwarf_read_uleb128(&ln, end); // size
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 = dwarf_read_2(ln, end);
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];
i = dwarf_read_1(ln, end);
if (i >= opcode_base) {
if (max_ops_per_insn == 1)
pc += ((i - opcode_base) / line_range) * min_insn_length;
else {
@ -928,7 +836,91 @@ check_pc:
if (pc >= wanted_pc && wanted_pc >= last_pc)
goto found;
line += i;
break;
}
else {
switch (i) {
case 0:
len = dwarf_read_uleb128(&ln, end);
cp = ln;
ln += len;
if (len == 0)
goto next_line;
switch (dwarf_read_1(cp, end)) {
case DW_LNE_end_sequence:
break;
case DW_LNE_set_address:
#if PTR_SIZE == 4
pc = dwarf_read_4(cp, end);
#else
pc = dwarf_read_8(cp, end);
#endif
opindex = 0;
break;
case DW_LNE_define_file: /* deprecated */
if (++filename_size < FILE_TABLE_SIZE) {
filename_table[filename_size - 1].name = (char *)ln - 1;
while (dwarf_read_1(ln, end)) {}
filename_table[filename_size - 1].dir_entry =
dwarf_read_uleb128(&ln, end);
}
else {
while (dwarf_read_1(ln, end)) {}
dwarf_read_uleb128(&ln, end);
}
dwarf_read_uleb128(&ln, end); // time
dwarf_read_uleb128(&ln, end); // size
break;
case DW_LNE_hi_user - 1:
function = (char *)cp;
func_addr = pc;
break;
default:
break;
}
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_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 = dwarf_read_2(ln, end);
pc += i;
opindex = 0;
i = 0;
goto check_pc;
default:
for (j = 0; j < opcode_length[i - 1]; j++)
dwarf_read_uleb128 (&ln, end);
break;
}
}
}
next_line:
@ -988,7 +980,7 @@ 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) {
if ((addr_t)rc->dwarf_text)
if (rc->dwarf)
pc = rt_printline_dwarf(rc, pc, level ? "by" : "at", skip);
else
pc = rt_printline(rc, pc, level ? "by" : "at", skip);