added computed gotos - better runtime error handling
This commit is contained in:
parent
fde824b7cd
commit
804d0c8d41
1 changed files with 181 additions and 67 deletions
248
tcc.c
248
tcc.c
|
@ -190,7 +190,7 @@ typedef struct AttributeDef {
|
||||||
#define MACRO_OBJ 0 /* object like macro */
|
#define MACRO_OBJ 0 /* object like macro */
|
||||||
#define MACRO_FUNC 1 /* function like macro */
|
#define MACRO_FUNC 1 /* function like macro */
|
||||||
|
|
||||||
/* field 'Sym.t' for labels */
|
/* field 'Sym.r' for labels */
|
||||||
#define LABEL_FORWARD 1 /* label is forward defined */
|
#define LABEL_FORWARD 1 /* label is forward defined */
|
||||||
|
|
||||||
/* type_decl() types */
|
/* type_decl() types */
|
||||||
|
@ -305,6 +305,10 @@ int gnu_ext = 1;
|
||||||
/* use Tiny C extensions */
|
/* use Tiny C extensions */
|
||||||
int tcc_ext = 1;
|
int tcc_ext = 1;
|
||||||
|
|
||||||
|
/* max number of callers shown if error */
|
||||||
|
static int num_callers = 6;
|
||||||
|
static const char **rt_bound_error_msg;
|
||||||
|
|
||||||
/* XXX: suppress that ASAP */
|
/* XXX: suppress that ASAP */
|
||||||
static struct TCCState *tcc_state;
|
static struct TCCState *tcc_state;
|
||||||
|
|
||||||
|
@ -572,7 +576,7 @@ int parse_btype(int *type_ptr, AttributeDef *ad);
|
||||||
int type_decl(AttributeDef *ad, int *v, int t, int td);
|
int type_decl(AttributeDef *ad, int *v, int t, int td);
|
||||||
|
|
||||||
void error(const char *fmt, ...);
|
void error(const char *fmt, ...);
|
||||||
void rt_error(unsigned long pc, const char *fmt, ...);
|
void rt_error(struct ucontext *uc, const char *fmt, ...);
|
||||||
void vpushi(int v);
|
void vpushi(int v);
|
||||||
void vset(int t, int r, int v);
|
void vset(int t, int r, int v);
|
||||||
void type_to_str(char *buf, int buf_size,
|
void type_to_str(char *buf, int buf_size,
|
||||||
|
@ -910,6 +914,7 @@ static void put_extern_sym(Sym *sym, Section *section,
|
||||||
name = get_tok_str(sym->v, NULL);
|
name = get_tok_str(sym->v, NULL);
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
if (do_bounds_check) {
|
if (do_bounds_check) {
|
||||||
|
/* XXX: avoid doing that for statics ? */
|
||||||
/* if bound checking is activated, we change some function
|
/* if bound checking is activated, we change some function
|
||||||
names by adding the "__bound" prefix */
|
names by adding the "__bound" prefix */
|
||||||
switch(sym->v) {
|
switch(sym->v) {
|
||||||
|
@ -5475,8 +5480,7 @@ static void unary(void)
|
||||||
test_lvalue();
|
test_lvalue();
|
||||||
vtop->t = mk_pointer(vtop->t);
|
vtop->t = mk_pointer(vtop->t);
|
||||||
gaddrof();
|
gaddrof();
|
||||||
} else
|
} else if (t == '!') {
|
||||||
if (t == '!') {
|
|
||||||
unary();
|
unary();
|
||||||
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST)
|
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST)
|
||||||
vtop->c.i = !vtop->c.i;
|
vtop->c.i = !vtop->c.i;
|
||||||
|
@ -5484,21 +5488,18 @@ static void unary(void)
|
||||||
vtop->c.i = vtop->c.i ^ 1;
|
vtop->c.i = vtop->c.i ^ 1;
|
||||||
else
|
else
|
||||||
vset(VT_INT, VT_JMP, gtst(1, 0));
|
vset(VT_INT, VT_JMP, gtst(1, 0));
|
||||||
} else
|
} else if (t == '~') {
|
||||||
if (t == '~') {
|
|
||||||
unary();
|
unary();
|
||||||
vpushi(-1);
|
vpushi(-1);
|
||||||
gen_op('^');
|
gen_op('^');
|
||||||
} else
|
} else if (t == '+') {
|
||||||
if (t == '+') {
|
|
||||||
/* in order to force cast, we add zero */
|
/* in order to force cast, we add zero */
|
||||||
unary();
|
unary();
|
||||||
if ((vtop->t & VT_BTYPE) == VT_PTR)
|
if ((vtop->t & VT_BTYPE) == VT_PTR)
|
||||||
error("pointer not accepted for unary plus");
|
error("pointer not accepted for unary plus");
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
gen_op('+');
|
gen_op('+');
|
||||||
} else
|
} else if (t == TOK_SIZEOF || t == TOK_ALIGNOF) {
|
||||||
if (t == TOK_SIZEOF || t == TOK_ALIGNOF) {
|
|
||||||
if (tok == '(') {
|
if (tok == '(') {
|
||||||
ft = parse_expr_type();
|
ft = parse_expr_type();
|
||||||
} else {
|
} else {
|
||||||
|
@ -5509,16 +5510,28 @@ static void unary(void)
|
||||||
vpushi(size);
|
vpushi(size);
|
||||||
else
|
else
|
||||||
vpushi(align);
|
vpushi(align);
|
||||||
} else
|
} else if (t == TOK_INC || t == TOK_DEC) {
|
||||||
if (t == TOK_INC || t == TOK_DEC) {
|
|
||||||
unary();
|
unary();
|
||||||
inc(0, t);
|
inc(0, t);
|
||||||
} else if (t == '-') {
|
} else if (t == '-') {
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
unary();
|
unary();
|
||||||
gen_op('-');
|
gen_op('-');
|
||||||
} else
|
} else if (t == TOK_LAND && gnu_ext) {
|
||||||
{
|
/* allow to take the address of a label */
|
||||||
|
if (tok < TOK_UIDENT)
|
||||||
|
expect("label identifier");
|
||||||
|
s = sym_find1(&label_stack, tok);
|
||||||
|
if (!s) {
|
||||||
|
s = sym_push1(&label_stack, tok, 0, 0);
|
||||||
|
s->r = LABEL_FORWARD;
|
||||||
|
}
|
||||||
|
if (!s->t)
|
||||||
|
s->t = mk_pointer(VT_VOID) | VT_STATIC;
|
||||||
|
vset(s->t, VT_CONST | VT_SYM, 0);
|
||||||
|
vtop->sym = s;
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
if (t < TOK_UIDENT)
|
if (t < TOK_UIDENT)
|
||||||
expect("identifier");
|
expect("identifier");
|
||||||
s = sym_find(t);
|
s = sym_find(t);
|
||||||
|
@ -6200,16 +6213,29 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_re
|
||||||
} else
|
} else
|
||||||
if (tok == TOK_GOTO) {
|
if (tok == TOK_GOTO) {
|
||||||
next();
|
next();
|
||||||
s = sym_find1(&label_stack, tok);
|
if (tok == '*' && gnu_ext) {
|
||||||
/* put forward definition if needed */
|
/* computed goto */
|
||||||
if (!s)
|
next();
|
||||||
s = sym_push1(&label_stack, tok, LABEL_FORWARD, 0);
|
gexpr();
|
||||||
/* label already defined */
|
if ((vtop->t & VT_BTYPE) != VT_PTR)
|
||||||
if (s->t & LABEL_FORWARD)
|
expect("pointer");
|
||||||
s->c = gjmp(s->c);
|
ggoto();
|
||||||
else
|
} else if (tok >= TOK_UIDENT) {
|
||||||
gjmp_addr(s->c);
|
s = sym_find1(&label_stack, tok);
|
||||||
next();
|
/* put forward definition if needed */
|
||||||
|
if (!s) {
|
||||||
|
s = sym_push1(&label_stack, tok, 0, 0);
|
||||||
|
s->r = LABEL_FORWARD;
|
||||||
|
}
|
||||||
|
/* label already defined */
|
||||||
|
if (s->r & LABEL_FORWARD)
|
||||||
|
s->next = (void *)gjmp((long)s->next);
|
||||||
|
else
|
||||||
|
gjmp_addr((long)s->next);
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
expect("label identifier");
|
||||||
|
}
|
||||||
skip(';');
|
skip(';');
|
||||||
} else {
|
} else {
|
||||||
b = is_label();
|
b = is_label();
|
||||||
|
@ -6217,14 +6243,14 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_re
|
||||||
/* label case */
|
/* label case */
|
||||||
s = sym_find1(&label_stack, b);
|
s = sym_find1(&label_stack, b);
|
||||||
if (s) {
|
if (s) {
|
||||||
if (!(s->t & LABEL_FORWARD))
|
if (!(s->r & LABEL_FORWARD))
|
||||||
error("multiple defined label");
|
error("multiple defined label");
|
||||||
gsym(s->c);
|
gsym((long)s->next);
|
||||||
s->c = ind;
|
|
||||||
s->t = 0;
|
|
||||||
} else {
|
} else {
|
||||||
sym_push1(&label_stack, b, 0, ind);
|
s = sym_push1(&label_stack, b, 0, 0);
|
||||||
}
|
}
|
||||||
|
s->next = (void *)ind;
|
||||||
|
s->r = 0;
|
||||||
/* we accept this, but it is a mistake */
|
/* we accept this, but it is a mistake */
|
||||||
if (tok == '}')
|
if (tok == '}')
|
||||||
warning("deprecated use of label at end of compound statement");
|
warning("deprecated use of label at end of compound statement");
|
||||||
|
@ -6997,6 +7023,22 @@ static void decl(int l)
|
||||||
gsym(rsym);
|
gsym(rsym);
|
||||||
gfunc_epilog();
|
gfunc_epilog();
|
||||||
cur_text_section->data_offset = ind;
|
cur_text_section->data_offset = ind;
|
||||||
|
/* look if any labels are undefined. Define symbols if
|
||||||
|
'&&label' was used. */
|
||||||
|
{
|
||||||
|
Sym *s;
|
||||||
|
for(s = label_stack.top; s != NULL; s = s->prev) {
|
||||||
|
if (s->r & LABEL_FORWARD) {
|
||||||
|
error("label '%s' used but not defined",
|
||||||
|
get_tok_str(s->v, NULL));
|
||||||
|
}
|
||||||
|
if (s->c) {
|
||||||
|
/* define corresponding symbol. A size of
|
||||||
|
1 is put. */
|
||||||
|
put_extern_sym(s, cur_text_section, (long)s->next, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
sym_pop(&label_stack, NULL); /* reset label stack */
|
sym_pop(&label_stack, NULL); /* reset label stack */
|
||||||
sym_pop(&local_stack, NULL); /* reset local stack */
|
sym_pop(&local_stack, NULL); /* reset local stack */
|
||||||
/* end of function */
|
/* end of function */
|
||||||
|
@ -7234,6 +7276,8 @@ static void rt_printline(unsigned long wanted_pc)
|
||||||
int incl_index, len, last_line_num, i;
|
int incl_index, len, last_line_num, i;
|
||||||
const char *str, *p;
|
const char *str, *p;
|
||||||
|
|
||||||
|
fprintf(stderr, "0x%08lx:", wanted_pc);
|
||||||
|
|
||||||
func_name[0] = '\0';
|
func_name[0] = '\0';
|
||||||
func_addr = 0;
|
func_addr = 0;
|
||||||
incl_index = 0;
|
incl_index = 0;
|
||||||
|
@ -7247,6 +7291,10 @@ static void rt_printline(unsigned long wanted_pc)
|
||||||
/* function start or end */
|
/* function start or end */
|
||||||
case N_FUN:
|
case N_FUN:
|
||||||
if (sym->n_strx == 0) {
|
if (sym->n_strx == 0) {
|
||||||
|
/* we test if between last line and end of function */
|
||||||
|
pc = sym->n_value + func_addr;
|
||||||
|
if (wanted_pc >= last_pc && wanted_pc < pc)
|
||||||
|
goto found;
|
||||||
func_name[0] = '\0';
|
func_name[0] = '\0';
|
||||||
func_addr = 0;
|
func_addr = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -7300,31 +7348,98 @@ static void rt_printline(unsigned long wanted_pc)
|
||||||
}
|
}
|
||||||
sym++;
|
sym++;
|
||||||
}
|
}
|
||||||
/* did not find line number info: */
|
|
||||||
fprintf(stderr, "(no debug info, pc=0x%08lx): ", wanted_pc);
|
/* second pass: we try symtab symbols (no line number info) */
|
||||||
|
incl_index = 0;
|
||||||
|
{
|
||||||
|
Elf32_Sym *sym, *sym_end;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset);
|
||||||
|
for(sym = (Elf32_Sym *)symtab_section->data + 1;
|
||||||
|
sym < sym_end;
|
||||||
|
sym++) {
|
||||||
|
type = ELF32_ST_TYPE(sym->st_info);
|
||||||
|
if (type == STT_FUNC) {
|
||||||
|
if (wanted_pc >= sym->st_value &&
|
||||||
|
wanted_pc < sym->st_value + sym->st_size) {
|
||||||
|
pstrcpy(last_func_name, sizeof(last_func_name),
|
||||||
|
strtab_section->data + sym->st_name);
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* did not find any info: */
|
||||||
|
fprintf(stderr, " ???\n");
|
||||||
return;
|
return;
|
||||||
found:
|
found:
|
||||||
for(i = 0; i < incl_index - 1; i++)
|
|
||||||
fprintf(stderr, "In file included from %s\n",
|
|
||||||
incl_files[i]);
|
|
||||||
if (incl_index > 0) {
|
|
||||||
fprintf(stderr, "%s:%d: ",
|
|
||||||
incl_files[incl_index - 1], last_line_num);
|
|
||||||
}
|
|
||||||
if (last_func_name[0] != '\0') {
|
if (last_func_name[0] != '\0') {
|
||||||
fprintf(stderr, "in function '%s()': ", last_func_name);
|
fprintf(stderr, " %s()", last_func_name);
|
||||||
}
|
}
|
||||||
|
if (incl_index > 0) {
|
||||||
|
fprintf(stderr, " (%s:%d",
|
||||||
|
incl_files[incl_index - 1], last_line_num);
|
||||||
|
for(i = incl_index - 2; i >= 0; i--)
|
||||||
|
fprintf(stderr, ", included from %s", incl_files[i]);
|
||||||
|
fprintf(stderr, ")");
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
|
||||||
|
#ifndef EIP
|
||||||
|
#define EIP 14
|
||||||
|
#define EBP 6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* return the PC at frame level 'level'. Return non zero if not found */
|
||||||
|
static int rt_get_caller_pc(unsigned long *paddr,
|
||||||
|
struct ucontext *uc, int level)
|
||||||
|
{
|
||||||
|
unsigned long fp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (level == 0) {
|
||||||
|
*paddr = uc->uc_mcontext.gregs[EIP];
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
fp = uc->uc_mcontext.gregs[EBP];
|
||||||
|
for(i=1;i<level;i++) {
|
||||||
|
/* XXX: check address validity with program info */
|
||||||
|
if (fp <= 0x1000 || fp >= 0xc0000000)
|
||||||
|
return -1;
|
||||||
|
fp = ((unsigned long *)fp)[0];
|
||||||
|
}
|
||||||
|
*paddr = ((unsigned long *)fp)[1];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error add corresponding function
|
||||||
|
#endif
|
||||||
|
|
||||||
/* emit a run time error at position 'pc' */
|
/* emit a run time error at position 'pc' */
|
||||||
void rt_error(unsigned long pc, const char *fmt, ...)
|
void rt_error(struct ucontext *uc, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
unsigned long pc;
|
||||||
|
int i;
|
||||||
|
|
||||||
rt_printline(pc);
|
va_start(ap, fmt);
|
||||||
|
fprintf(stderr, "Runtime error: ");
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
for(i=0;i<num_callers;i++) {
|
||||||
|
if (rt_get_caller_pc(&pc, uc, i) < 0)
|
||||||
|
break;
|
||||||
|
if (i == 0)
|
||||||
|
fprintf(stderr, "at ");
|
||||||
|
else
|
||||||
|
fprintf(stderr, "by ");
|
||||||
|
rt_printline(pc);
|
||||||
|
}
|
||||||
exit(255);
|
exit(255);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
@ -7334,38 +7449,34 @@ void rt_error(unsigned long pc, const char *fmt, ...)
|
||||||
static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
||||||
{
|
{
|
||||||
struct ucontext *uc = puc;
|
struct ucontext *uc = puc;
|
||||||
unsigned long pc;
|
|
||||||
|
|
||||||
#ifdef __i386__
|
|
||||||
pc = uc->uc_mcontext.gregs[14];
|
|
||||||
#else
|
|
||||||
#error please put the right sigcontext field
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch(signum) {
|
switch(signum) {
|
||||||
case SIGFPE:
|
case SIGFPE:
|
||||||
switch(siginf->si_code) {
|
switch(siginf->si_code) {
|
||||||
case FPE_INTDIV:
|
case FPE_INTDIV:
|
||||||
case FPE_FLTDIV:
|
case FPE_FLTDIV:
|
||||||
rt_error(pc, "division by zero");
|
rt_error(uc, "division by zero");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rt_error(pc, "floating point exception");
|
rt_error(uc, "floating point exception");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SIGBUS:
|
case SIGBUS:
|
||||||
case SIGSEGV:
|
case SIGSEGV:
|
||||||
rt_error(pc, "dereferencing invalid pointer");
|
if (rt_bound_error_msg && *rt_bound_error_msg)
|
||||||
|
rt_error(uc, *rt_bound_error_msg);
|
||||||
|
else
|
||||||
|
rt_error(uc, "dereferencing invalid pointer");
|
||||||
break;
|
break;
|
||||||
case SIGILL:
|
case SIGILL:
|
||||||
rt_error(pc, "illegal instruction");
|
rt_error(uc, "illegal instruction");
|
||||||
break;
|
break;
|
||||||
case SIGABRT:
|
case SIGABRT:
|
||||||
rt_error(pc, "abort() called");
|
rt_error(uc, "abort() called");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rt_error(pc, "caught signal %d", signum);
|
rt_error(uc, "caught signal %d", signum);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
exit(255);
|
exit(255);
|
||||||
|
@ -7440,11 +7551,9 @@ int tcc_run(TCCState *s1, int argc, char **argv)
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
if (do_bounds_check) {
|
if (do_bounds_check) {
|
||||||
void (*bound_init)(void);
|
void (*bound_init)(void);
|
||||||
void **bound_error_func;
|
|
||||||
|
|
||||||
/* set error function */
|
/* set error function */
|
||||||
bound_error_func = (void **)tcc_get_symbol(s1, "__bound_error_func");
|
rt_bound_error_msg = (void *)tcc_get_symbol(s1, "__bound_error_msg");
|
||||||
*bound_error_func = rt_error;
|
|
||||||
|
|
||||||
/* XXX: use .init section so that it also work in binary ? */
|
/* XXX: use .init section so that it also work in binary ? */
|
||||||
bound_init = (void *)tcc_get_symbol(s1, "__bound_init");
|
bound_init = (void *)tcc_get_symbol(s1, "__bound_init");
|
||||||
|
@ -7782,9 +7891,9 @@ int tcc_set_output_type(TCCState *s, int output_type)
|
||||||
|
|
||||||
void help(void)
|
void help(void)
|
||||||
{
|
{
|
||||||
printf("tcc version 0.9.12 - Tiny C Compiler - Copyright (C) 2001, 2002 Fabrice Bellard\n"
|
printf("tcc version 0.9.13 - Tiny C Compiler - Copyright (C) 2001, 2002 Fabrice Bellard\n"
|
||||||
"usage: tcc [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n"
|
"usage: tcc [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n"
|
||||||
" [-g] [-b] [-Ldir] [-llib] [-shared] [-static]\n"
|
" [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-static]\n"
|
||||||
" [--] infile1 [infile2... --] [infile_args...]\n"
|
" [--] infile1 [infile2... --] [infile_args...]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"General options:\n"
|
"General options:\n"
|
||||||
|
@ -7798,17 +7907,18 @@ void help(void)
|
||||||
" -Idir add include path 'dir'\n"
|
" -Idir add include path 'dir'\n"
|
||||||
" -Dsym[=val] define 'sym' with value 'val'\n"
|
" -Dsym[=val] define 'sym' with value 'val'\n"
|
||||||
" -Usym undefine 'sym'\n"
|
" -Usym undefine 'sym'\n"
|
||||||
"C compiler options:\n"
|
|
||||||
" -g generate runtime debug info\n"
|
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
|
||||||
" -b compile with built-in memory and bounds checker (implies -g)\n"
|
|
||||||
#endif
|
|
||||||
"Linker options:\n"
|
"Linker options:\n"
|
||||||
" -Ldir add library path 'dir'\n"
|
" -Ldir add library path 'dir'\n"
|
||||||
" -llib link with dynamic or static library 'lib'\n"
|
" -llib link with dynamic or static library 'lib'\n"
|
||||||
" -shared generate a shared library\n"
|
" -shared generate a shared library\n"
|
||||||
" -static static linking\n"
|
" -static static linking\n"
|
||||||
" -r relocatable output\n"
|
" -r relocatable output\n"
|
||||||
|
"Debugger options:\n"
|
||||||
|
" -g generate runtime debug info\n"
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
|
" -b compile with built-in memory and bounds checker (implies -g)\n"
|
||||||
|
#endif
|
||||||
|
" -bt N show N callers in stack traces\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7884,7 +7994,9 @@ int main(int argc, char **argv)
|
||||||
nb_libraries++;
|
nb_libraries++;
|
||||||
} else if (!strcmp(r + 1, "bench")) {
|
} else if (!strcmp(r + 1, "bench")) {
|
||||||
do_bench = 1;
|
do_bench = 1;
|
||||||
} else
|
} else if (!strcmp(r + 1, "bt")) {
|
||||||
|
num_callers = atoi(argv[optind++]);
|
||||||
|
} else
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
if (r[1] == 'b') {
|
if (r[1] == 'b') {
|
||||||
do_bounds_check = 1;
|
do_bounds_check = 1;
|
||||||
|
@ -7982,7 +8094,9 @@ int main(int argc, char **argv)
|
||||||
ret = tcc_run(s, argc - optind, argv + optind);
|
ret = tcc_run(s, argc - optind, argv + optind);
|
||||||
}
|
}
|
||||||
the_end:
|
the_end:
|
||||||
tcc_delete(s);
|
/* XXX: cannot do it with bound checking because of the malloc hooks */
|
||||||
|
if (!do_bounds_check)
|
||||||
|
tcc_delete(s);
|
||||||
|
|
||||||
#ifdef MEM_DEBUG
|
#ifdef MEM_DEBUG
|
||||||
if (do_bench) {
|
if (do_bench) {
|
||||||
|
|
Loading…
Reference in a new issue