History

backtrace: test with DLLs

- tests2/113_btdll.c: test handling multiple stabs infos Also: - libtcc.c: remove _ISOC99_SOURCE pre-defines. It is causing strange warnings such as 'strdup not declared' - i386/x86_64-gen.c cleanup bounds_pro/epilog. This discards the extra code for main's argv. If needed, __argv might be processed instead. - tccgen.c:block(): reduce stackspace usage. For example with code like "if (..) ... else if (..) ... else if (..)... " considerable numbers of nested block() calls may occur. Before that most stack space used when compiling itself was for libtcc.c:tcc_set_linker(). Now it's rather this construct at tccpp.c:2765: in next_nomacro1(): if (!((isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) || c == '.' || ((c == '+' || c == '-') ...

grischka committed 6 years ago

Commit d79e1de1 parent a5f6e6113 files · +209 −218Browse files

Unified · Split

13 files
  1. i386-gen.c +44 −43
  2. lib/bcheck.c +2 −1
  3. libtcc.c +0 −10
  4. tcc.h +3 −0
  5. tccelf.c +4 −0
  6. tccgen.c +25 −27
  7. tccrun.c +5 −5
  8. tests/tests2/112_backtrace.expect +0 −22
  9. tests/tests2/113_btdll.c +43 −0
  10. tests/tests2/113_btdll.expect +6 −0
  11. tests/tests2/Makefile +20 −11
  12. win32/build-tcc.bat +1 −1
  13. x86_64-gen.c +56 −98
i386-gen.c+44−43
@@ -97,6 +97,8 @@ static int func_ret_sub; · 96 unmodified lines
97#ifdef CONFIG_TCC_BCHECK97#ifdef CONFIG_TCC_BCHECK
98static addr_t func_bound_offset;98static addr_t func_bound_offset;
99static unsigned long func_bound_ind;99static unsigned long func_bound_ind;
100static void gen_bounds_prolog(void);
101static void gen_bounds_epilog(void);
100#endif102#endif
101 103
102/* XXX: make it faster ? */104/* XXX: make it faster ? */
@@ -480,6 +482,7 @@ ST_FUNC void gfunc_call(int nb_args) · 377 unmodified lines
480 else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT)482 else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT)
481 args_size -= 4;483 args_size -= 4;
482#endif484#endif
485
483 gcall_or_jmp(0);486 gcall_or_jmp(0);
484 487
485 if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)488 if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
@@ -499,7 +502,6 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) · 13 unmodified lines
499 CType *func_type = &func_sym->type;502 CType *func_type = &func_sym->type;
500 int addr, align, size, func_call, fastcall_nb_regs;503 int addr, align, size, func_call, fastcall_nb_regs;
501 int param_index, param_addr;504 int param_index, param_addr;
502 int n_arg = 0;
503 uint8_t *fastcall_regs_ptr;505 uint8_t *fastcall_regs_ptr;
504 Sym *sym;506 Sym *sym;
505 CType *type;507 CType *type;
@@ -542,7 +544,6 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) · 36 unmodified lines
542 }544 }
543 /* define parameters */545 /* define parameters */
544 while ((sym = sym->next) != NULL) {546 while ((sym = sym->next) != NULL) {
545 n_arg++;
546 type = &sym->type;547 type = &sym->type;
547 size = type_size(type, &align);548 size = type_size(type, &align);
548 size = (size + 3) & ~3;549 size = (size + 3) & ~3;
@@ -576,19 +577,8 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) · 27 unmodified lines
576#endif577#endif
577 578
578#ifdef CONFIG_TCC_BCHECK579#ifdef CONFIG_TCC_BCHECK
579 /* leave some room for bound checking code */580 if (tcc_state->do_bounds_check)
580 if (tcc_state->do_bounds_check) {581 gen_bounds_prolog();
581 func_bound_offset = lbounds_section->data_offset;
582 func_bound_ind = ind;
583 oad(0xb8, 0); /* lbound section pointer */
584 oad(0xb8, 0); /* call to function */
585 if (n_arg >= 2 && strcmp (get_tok_str(func_sym->v, NULL), "main") == 0) {
586 o(0x0c458b); /* mov 0x12(%ebp),%eax */
587 o(0x50); /* push %eax */
588 gen_static_call(TOK___bound_main_arg);
589 o(0x04c483); /* add $0x4,%esp */
590 }
591 }
592#endif582#endif
593}583}
594 584
@@ -598,34 +588,8 @@ ST_FUNC void gfunc_epilog(void) · 3 unmodified lines
598 addr_t v, saved_ind;588 addr_t v, saved_ind;
599 589
600#ifdef CONFIG_TCC_BCHECK590#ifdef CONFIG_TCC_BCHECK
601 if (tcc_state->do_bounds_check591 if (tcc_state->do_bounds_check)
602 && func_bound_offset != lbounds_section->data_offset) {592 gen_bounds_epilog();
603 addr_t saved_ind;
604 addr_t *bounds_ptr;
605 Sym *sym_data;
606
607 /* add end of table info */
608 bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
609 *bounds_ptr = 0;
610
611 /* generate bound local allocation */
612 saved_ind = ind;
613 ind = func_bound_ind;
614 sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
615 func_bound_offset, lbounds_section->data_offset);
616 greloc(cur_text_section, sym_data,
617 ind + 1, R_386_32);
618 oad(0xb8, 0); /* mov %eax, xxx */
619 gen_static_call(TOK___bound_local_new);
620 ind = saved_ind;
621
622 /* generate bound check local freeing */
623 o(0x5250); /* save returned value, if any */
624 greloc(cur_text_section, sym_data, ind + 1, R_386_32);
625 oad(0xb8, 0); /* mov %eax, xxx */
626 gen_static_call(TOK___bound_local_delete);
627 o(0x585a); /* restore returned value, if any */
628 }
629#endif593#endif
630 594
631 /* align local size to word & save local variables */595 /* align local size to word & save local variables */
@@ -1096,6 +1060,43 @@ ST_FUNC void gen_bounded_ptr_deref(void) · 464 unmodified lines
1096 rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);1060 rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
1097 rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));1061 rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
1098}1062}
1063
1064static void gen_bounds_prolog(void)
1065{
1066 /* leave some room for bound checking code */
1067 func_bound_offset = lbounds_section->data_offset;
1068 func_bound_ind = ind;
1069 oad(0xb8, 0); /* lbound section pointer */
1070 oad(0xb8, 0); /* call to function */
1071}
1072
1073static void gen_bounds_epilog(void)
1074{
1075 addr_t saved_ind;
1076 addr_t *bounds_ptr;
1077 Sym *sym_data;
1078
1079 /* add end of table info */
1080 bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
1081 *bounds_ptr = 0;
1082
1083 /* generate bound local allocation */
1084 saved_ind = ind;
1085 ind = func_bound_ind;
1086 sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
1087 func_bound_offset, lbounds_section->data_offset);
1088 greloc(cur_text_section, sym_data, ind + 1, R_386_32);
1089 ind = ind + 5;
1090 gen_static_call(TOK___bound_local_new);
1091 ind = saved_ind;
1092
1093 /* generate bound check local freeing */
1094 o(0x5250); /* save returned value, if any */
1095 greloc(cur_text_section, sym_data, ind + 1, R_386_32);
1096 oad(0xb8, 0); /* mov %eax, xxx */
1097 gen_static_call(TOK___bound_local_delete);
1098 o(0x585a); /* restore returned value, if any */
1099}
1099#endif1100#endif
1100 1101
1101/* Save the stack pointer onto the stack */1102/* Save the stack pointer onto the stack */
lib/bcheck.c+2−1
@@ -353,7 +353,8 @@ void * __bound_ptr_add(void *p, size_t offset) · 352 unmodified lines
353 if (addr <= tree->size) {353 if (addr <= tree->size) {
354 if (tree->is_invalid || addr + offset > tree->size) {354 if (tree->is_invalid || addr + offset > tree->size) {
355 POST_SEM ();355 POST_SEM ();
356 bound_warning("%p is outside of the region", p + offset);356 if (print_warn_ptr_add)
357 bound_warning("%p is outside of the region", p + offset);
357 if (never_fatal <= 0)358 if (never_fatal <= 0)
358 return INVALID_POINTER; /* return an invalid pointer */359 return INVALID_POINTER; /* return an invalid pointer */
359 return p + offset;360 return p + offset;
libtcc.c+0−10
@@ -802,11 +802,6 @@ LIBTCCAPI TCCState *tcc_new(void) · 801 unmodified lines
802 tcc_define_symbol(s, "__STDC_VERSION__", "199901L");802 tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
803 tcc_define_symbol(s, "__STDC_HOSTED__", NULL);803 tcc_define_symbol(s, "__STDC_HOSTED__", NULL);
804 804
805#if !defined(TCC_TARGET_PE)
806 /* glibc compatible macro (default for C99) */
807 tcc_define_symbol(s, "_ISOC99_SOURCE", "1");
808#endif
809
810 /* target defines */805 /* target defines */
811#if defined(TCC_TARGET_I386)806#if defined(TCC_TARGET_I386)
812 tcc_define_symbol(s, "__i386__", NULL);807 tcc_define_symbol(s, "__i386__", NULL);
@@ -1905,11 +1900,6 @@ reparse: · 1092 unmodified lines
1905 * encoding used is implementationdefined.1900 * encoding used is implementationdefined.
1906 */1901 */
1907 tcc_define_symbol(s, "__STDC_UTF_32__", "1");1902 tcc_define_symbol(s, "__STDC_UTF_32__", "1");
1908 /*
1909 * glibc compatible macro used when -std=c11 is used.
1910 * _ISOC99_SOURCE remains defined as does gcc.
1911 */
1912 tcc_define_symbol(s, "_ISOC11_SOURCE", "1");
1913#endif /* !TCC_TARGET_PE */1903#endif /* !TCC_TARGET_PE */
1914 s->cversion = 201112;1904 s->cversion = 201112;
1915 }1905 }
tcc.h+3−0
@@ -884,6 +884,9 @@ struct TCCState { · 883 unmodified lines
884 const char *runtime_main;884 const char *runtime_main;
885 void **runtime_mem;885 void **runtime_mem;
886 int nb_runtime_mem;886 int nb_runtime_mem;
887#endif
888
889#ifdef CONFIG_TCC_BACKTRACE
887 int rt_num_callers;890 int rt_num_callers;
888#endif891#endif
889 892
tccelf.c+4−0
@@ -1387,7 +1387,11 @@ ST_FUNC void tcc_add_btstub(TCCState *s1) · 1386 unmodified lines
1387 "__attribute__((constructor)) static void __bt_init_rt(){");1387 "__attribute__((constructor)) static void __bt_init_rt(){");
1388#ifdef TCC_TARGET_PE1388#ifdef TCC_TARGET_PE
1389 if (s1->output_type == TCC_OUTPUT_DLL)1389 if (s1->output_type == TCC_OUTPUT_DLL)
1390#ifdef CONFIG_TCC_BCHECK
1390 cstr_printf(&cstr, "__bt_init_dll(%d);", s1->do_bounds_check);1391 cstr_printf(&cstr, "__bt_init_dll(%d);", s1->do_bounds_check);
1392#else
1393 cstr_printf(&cstr, "__bt_init_dll(0);");
1394#endif
1391#endif1395#endif
1392 cstr_printf(&cstr, "__bt_init(__rt_info,%d);}",1396 cstr_printf(&cstr, "__bt_init(__rt_info,%d);}",
1393 s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1);1397 s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1);
tccgen.c+25−27
@@ -101,6 +101,8 @@ ST_DATA struct switch_t { · 100 unmodified lines
101 int def_sym; /* default symbol */101 int def_sym; /* default symbol */
102 int *bsym;102 int *bsym;
103 struct scope *scope;103 struct scope *scope;
104 struct switch_t *prev;
105 SValue sv;
104} *cur_switch; /* current switch */106} *cur_switch; /* current switch */
105 107
106#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8108#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8
@@ -6447,6 +6449,7 @@ static void lblock(int *bsym, int *csym) · 6340 unmodified lines
6447static void block(int is_expr)6449static void block(int is_expr)
6448{6450{
6449 int a, b, c, d, e, t;6451 int a, b, c, d, e, t;
6452 struct scope o;
6450 Sym *s;6453 Sym *s;
6451 6454
6452 if (is_expr) {6455 if (is_expr) {
@@ -6487,7 +6490,6 @@ again: · 34 unmodified lines
6487 gsym(a);6490 gsym(a);
6488 6491
6489 } else if (t == '{') {6492 } else if (t == '{') {
6490 struct scope o;
6491 new_scope(&o);6493 new_scope(&o);
6492 6494
6493 /* handle local labels declarations */6495 /* handle local labels declarations */
@@ -6545,10 +6547,10 @@ again: · 51 unmodified lines
6545 /* compute jump */6547 /* compute jump */
6546 if (!cur_scope->bsym)6548 if (!cur_scope->bsym)
6547 tcc_error("cannot break");6549 tcc_error("cannot break");
6548 if (!cur_switch || cur_scope->bsym != cur_switch->bsym)6550 if (cur_switch && cur_scope->bsym == cur_switch->bsym)
6549 leave_scope(loop_scope);
6550 else
6551 leave_scope(cur_switch->scope);6551 leave_scope(cur_switch->scope);
6552 else
6553 leave_scope(loop_scope);
6552 *cur_scope->bsym = gjmp(*cur_scope->bsym);6554 *cur_scope->bsym = gjmp(*cur_scope->bsym);
6553 skip(';');6555 skip(';');
6554 6556
@@ -6561,7 +6563,6 @@ again: · 6 unmodified lines
6561 skip(';');6563 skip(';');
6562 6564
6563 } else if (t == TOK_FOR) {6565 } else if (t == TOK_FOR) {
6564 struct scope o;
6565 new_scope(&o);6566 new_scope(&o);
6566 6567
6567 skip('(');6568 skip('(');
@@ -6611,22 +6612,18 @@ again: · 43 unmodified lines
6611 gsym(a);6612 gsym(a);
6612 6613
6613 } else if (t == TOK_SWITCH) {6614 } else if (t == TOK_SWITCH) {
6614 struct switch_t *saved, sw;6615 struct switch_t *sw;
6615 SValue switchval;
6616
6617 sw.p = NULL;
6618 sw.n = 0;
6619 sw.def_sym = 0;
6620 sw.bsym = &a;
6621 sw.scope = cur_scope;
6622 6616
6623 saved = cur_switch;6617 sw = tcc_mallocz(sizeof *sw);
6624 cur_switch = &sw;6618 sw->bsym = &a;
6619 sw->scope = cur_scope;
6620 sw->prev = cur_switch;
6621 cur_switch = sw;
6625 6622
6626 skip('(');6623 skip('(');
6627 gexpr();6624 gexpr();
6628 skip(')');6625 skip(')');
6629 switchval = *vtop--;6626 sw->sv = *vtop--; /* save switch value */
6630 6627
6631 a = 0;6628 a = 0;
6632 b = gjmp(0); /* jump to first case */6629 b = gjmp(0); /* jump to first case */
@@ -6635,28 +6632,29 @@ again: · 2 unmodified lines
6635 /* case lookup */6632 /* case lookup */
6636 gsym(b);6633 gsym(b);
6637 6634
6638 qsort(sw.p, sw.n, sizeof(void*), case_cmp);6635 qsort(sw->p, sw->n, sizeof(void*), case_cmp);
6639 for (b = 1; b < sw.n; b++)6636 for (b = 1; b < sw->n; b++)
6640 if (sw.p[b - 1]->v2 >= sw.p[b]->v1)6637 if (sw->p[b - 1]->v2 >= sw->p[b]->v1)
6641 tcc_error("duplicate case value");6638 tcc_error("duplicate case value");
6642 6639
6643 /* Our switch table sorting is signed, so the compared6640 /* Our switch table sorting is signed, so the compared
6644 value needs to be as well when it's 64bit. */6641 value needs to be as well when it's 64bit. */
6645 if ((switchval.type.t & VT_BTYPE) == VT_LLONG)6642 vpushv(&sw->sv);
6646 switchval.type.t &= ~VT_UNSIGNED;6643 if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
6647 vpushv(&switchval);6644 vtop->type.t &= ~VT_UNSIGNED;
6648 gv(RC_INT);6645 gv(RC_INT);
6649 d = 0, gcase(sw.p, sw.n, &d);6646 d = 0, gcase(sw->p, sw->n, &d);
6650 vpop();6647 vpop();
6651 if (sw.def_sym)6648 if (sw->def_sym)
6652 gsym_addr(d, sw.def_sym);6649 gsym_addr(d, sw->def_sym);
6653 else6650 else
6654 gsym(d);6651 gsym(d);
6655 /* break label */6652 /* break label */
6656 gsym(a);6653 gsym(a);
6657 6654
6658 dynarray_reset(&sw.p, &sw.n);6655 dynarray_reset(&sw->p, &sw->n);
6659 cur_switch = saved;6656 cur_switch = sw->prev;
6657 tcc_free(sw);
6660 6658
6661 } else if (t == TOK_CASE) {6659 } else if (t == TOK_CASE) {
6662 struct case_t *cr = tcc_malloc(sizeof(struct case_t));6660 struct case_t *cr = tcc_malloc(sizeof(struct case_t));
tccrun.c+5−5
@@ -48,7 +48,7 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap); · 47 unmodified lines
48static void rt_exit(int code);48static void rt_exit(int code);
49#endif /* CONFIG_TCC_BACKTRACE */49#endif /* CONFIG_TCC_BACKTRACE */
50 50
51/* defined when included from lib/bt.c */51/* defined when included from lib/bt-exe.c */
52#ifndef CONFIG_TCC_BACKTRACE_ONLY52#ifndef CONFIG_TCC_BACKTRACE_ONLY
53 53
54#ifndef _WIN3254#ifndef _WIN32
@@ -412,15 +412,15 @@ next: · 357 unmodified lines
412 /* Stab_Sym.n_value is only 32bits */412 /* Stab_Sym.n_value is only 32bits */
413 pc += rc->prog_base;413 pc += rc->prog_base;
414#endif414#endif
415 break;415 goto check_pc;
416 rel_pc:416 rel_pc:
417 pc += func_addr;417 pc += func_addr;
418 check_pc:
419 if (pc >= wanted_pc && wanted_pc >= last_pc)
420 goto found;
418 break;421 break;
419 }422 }
420 423
421 if (pc >= wanted_pc && wanted_pc >= last_pc)
422 goto found;
423
424 switch(sym->n_type) {424 switch(sym->n_type) {
425 /* function start or end */425 /* function start or end */
426 case N_FUN:426 case N_FUN:
tests/tests2/112_backtrace.expect+0−22
@@ -12,8 +12,6 @@ · 11 unmodified lines
12[test_bcheck_1]12[test_bcheck_1]
13* main13* main
14* f1()14* f1()
15112_backtrace.c:38: at f1: BCHECK: ........ is outside of the region
16112_backtrace.c:43: by main
17112_backtrace.c:38: at f1: BCHECK: invalid pointer ........, size 0x? in memmove dest15112_backtrace.c:38: at f1: BCHECK: invalid pointer ........, size 0x? in memmove dest
18112_backtrace.c:43: by main16112_backtrace.c:43: by main
19[returns 255]17[returns 255]
@@ -32,12 +30,10 @@ · 12 unmodified lines
32[returns 1]30[returns 1]
33 31
34[test_bcheck_100]32[test_bcheck_100]
35112_backtrace.c:107: at main: BCHECK: ........ is outside of the region
36112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0x? in memcpy dest33112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0x? in memcpy dest
37[returns 255]34[returns 255]
38 35
39[test_bcheck_101]36[test_bcheck_101]
40112_backtrace.c:109: at main: BCHECK: ........ is outside of the region
41112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0x? in memcpy src37112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0x? in memcpy src
42[returns 255]38[returns 255]
43 39
@@ -50,42 +46,34 @@ · 6 unmodified lines
50[returns 255]46[returns 255]
51 47
52[test_bcheck_104]48[test_bcheck_104]
53112_backtrace.c:115: at main: BCHECK: ........ is outside of the region
54112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s149112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s1
55[returns 255]50[returns 255]
56 51
57[test_bcheck_105]52[test_bcheck_105]
58112_backtrace.c:117: at main: BCHECK: ........ is outside of the region
59112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s253112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s2
60[returns 255]54[returns 255]
61 55
62[test_bcheck_106]56[test_bcheck_106]
63112_backtrace.c:119: at main: BCHECK: ........ is outside of the region
64112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0x? in memmove dest57112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0x? in memmove dest
65[returns 255]58[returns 255]
66 59
67[test_bcheck_107]60[test_bcheck_107]
68112_backtrace.c:121: at main: BCHECK: ........ is outside of the region
69112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0x? in memmove src61112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0x? in memmove src
70[returns 255]62[returns 255]
71 63
72[test_bcheck_108]64[test_bcheck_108]
73112_backtrace.c:123: at main: BCHECK: ........ is outside of the region
74112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0x? in memset65112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0x? in memset
75[returns 255]66[returns 255]
76 67
77[test_bcheck_109]68[test_bcheck_109]
78112_backtrace.c:125: at main: BCHECK: ........ is outside of the region
79112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0x? in strlen69112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0x? in strlen
80[returns 255]70[returns 255]
81 71
82[test_bcheck_110]72[test_bcheck_110]
83112_backtrace.c:127: at main: BCHECK: ........ is outside of the region
84112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x? in strcpy dest73112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x? in strcpy dest
85[returns 255]74[returns 255]
86 75
87[test_bcheck_111]76[test_bcheck_111]
88112_backtrace.c:129: at main: BCHECK: ........ is outside of the region
89112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x? in strcpy src77112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x? in strcpy src
90[returns 255]78[returns 255]
91 79
@@ -98,12 +86,10 @@ · 6 unmodified lines
98[returns 255]86[returns 255]
99 87
100[test_bcheck_114]88[test_bcheck_114]
101112_backtrace.c:135: at main: BCHECK: ........ is outside of the region
102112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x? in strncpy dest89112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x? in strncpy dest
103[returns 255]90[returns 255]
104 91
105[test_bcheck_115]92[test_bcheck_115]
106112_backtrace.c:137: at main: BCHECK: ........ is outside of the region
107112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x? in strncpy src93112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x? in strncpy src
108[returns 255]94[returns 255]
109 95
@@ -116,32 +102,26 @@ · 6 unmodified lines
116[returns 255]102[returns 255]
117 103
118[test_bcheck_118]104[test_bcheck_118]
119112_backtrace.c:143: at main: BCHECK: ........ is outside of the region
120112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s1105112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s1
121[returns 255]106[returns 255]
122 107
123[test_bcheck_119]108[test_bcheck_119]
124112_backtrace.c:145: at main: BCHECK: ........ is outside of the region
125112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s2109112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s2
126[returns 255]110[returns 255]
127 111
128[test_bcheck_120]112[test_bcheck_120]
129112_backtrace.c:147: at main: BCHECK: ........ is outside of the region
130112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s1113112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s1
131[returns 255]114[returns 255]
132 115
133[test_bcheck_121]116[test_bcheck_121]
134112_backtrace.c:149: at main: BCHECK: ........ is outside of the region
135112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s2117112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s2
136[returns 255]118[returns 255]
137 119
138[test_bcheck_122]120[test_bcheck_122]
139112_backtrace.c:151: at main: BCHECK: ........ is outside of the region
140112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest121112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest
141[returns 255]122[returns 255]
142 123
143[test_bcheck_123]124[test_bcheck_123]
144112_backtrace.c:153: at main: BCHECK: ........ is outside of the region
145112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest125112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest
146[returns 255]126[returns 255]
147 127
@@ -154,11 +134,9 @@ · 6 unmodified lines
154[returns 255]134[returns 255]
155 135
156[test_bcheck_126]136[test_bcheck_126]
157112_backtrace.c:159: at main: BCHECK: ........ is outside of the region
158112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0x? in strchr137112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0x? in strchr
159[returns 255]138[returns 255]
160 139
161[test_bcheck_127]140[test_bcheck_127]
162112_backtrace.c:161: at main: BCHECK: ........ is outside of the region
163112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0x? in strdup141112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0x? in strdup
164[returns 255]142[returns 255]
tests/tests2/113_btdll.c+43−0
@@ -0,0 +1,43 @@
1int tcc_backtrace(const char*, ...);
2#define hello() \
3 tcc_backtrace("hello from %s() / %s:%d",__FUNCTION__,__FILE__,__LINE__)
4
5#ifndef _WIN32
6# define __declspec(n)
7#endif
8
9#if DLL==1
10__declspec(dllexport) int f_1()
11{
12 hello();
13 return 0;
14}
15
16
17#elif DLL==2
18__declspec(dllexport) int f_2()
19{
20 hello();
21 return 0;
22}
23
24
25#else
26
27int f_1();
28int f_2();
29int f_main()
30{
31 hello();
32 return 0;
33}
34
35int main ()
36{
37 f_1();
38 f_2();
39 f_main();
40 return 0;
41}
42
43#endif
tests/tests2/113_btdll.expect+6−0
@@ -0,0 +1,6 @@
1113_btdll.c:12: at f_1: hello from f_1() / 113_btdll.c:12
2113_btdll.c:37: by main
3113_btdll.c:20: at f_2: hello from f_2() / 113_btdll.c:20
4113_btdll.c:38: by main
5113_btdll.c:31: at f_main: hello from f_main() / 113_btdll.c:31
6113_btdll.c:39: by main
tests/tests2/Makefile+20−11
@@ -24,7 +24,7 @@ ifeq (,$(filter i386,$(ARCH))) · 23 unmodified lines
24endif24endif
25ifeq (,$(filter i386 x86_64,$(ARCH)))25ifeq (,$(filter i386 x86_64,$(ARCH)))
26 SKIP += 85_asm-outside-function.test26 SKIP += 85_asm-outside-function.test
27 SKIP += 112_backtrace.test27 SKIP += 112_backtrace.test 113_btdll.test
28endif28endif
29ifeq (-$(findstring gcc,$(CC))-,--)29ifeq (-$(findstring gcc,$(CC))-,--)
30 SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))30 SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
@@ -61,7 +61,7 @@ GEN-ALWAYS = · 30 unmodified lines
6195_bitfields_ms.test : GEN = $(GEN-MSC)6195_bitfields_ms.test : GEN = $(GEN-MSC)
62 62
63# this test compiles/links two files:63# this test compiles/links two files:
64104_inline.test : FLAGS += $(SRC)/104+_inline.c64104_inline.test : FLAGS += $(subst 104,104+,$1)
65104_inline.test : GEN = $(GEN-TCC)65104_inline.test : GEN = $(GEN-TCC)
66 66
67# this test needs pthread67# this test needs pthread
@@ -72,7 +72,16 @@ GEN-ALWAYS = · 4 unmodified lines
72108_constructor.test: NORUN = true72108_constructor.test: NORUN = true
73 73
74112_backtrace.test: FLAGS += -dt -b74112_backtrace.test: FLAGS += -dt -b
75112_backtrace.test: FILTER += -e 's;[0-9A-Fa-fx]\{8,\};........;g' -e 's;0x[0-9A-Fa-f]\+;0x?;g'75112_backtrace.test 113_btdll.test: FILTER += \
76 -e 's;[0-9A-Fa-fx]\{8,\};........;g' \
77 -e 's;0x[0-9A-Fa-f]\+;0x?;g'
78
79# this test creates two DLLs and an EXE
80113_btdll.test: NORUN = true
81113_btdll.test: FLAGS += \
82 -bt $1 -shared -D DLL=1 -o a1$(DLLSUF) && $(TCC) \
83 -bt $1 -shared -D DLL=2 -o a2$(DLLSUF) && $(TCC) \
84 -bt a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=.
76 85
77# Filter source directory in warnings/errors (out-of-tree builds)86# Filter source directory in warnings/errors (out-of-tree builds)
78FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'87FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'
@@ -81,10 +90,10 @@ all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ; · 2 unmodified lines
81 90
82%.test: %.c %.expect91%.test: %.c %.expect
83 @echo Test: $*...92 @echo Test: $*...
84 @$(if $(NORUN),$(T1),$(T2)) $(if $(NODIFF),,$(T3))93 @$(call T1,$<) $(T3)
85 94
86T1 = $(TCC) $(FLAGS) $< -o a.exe && ./a.exe $(ARGS)95T1 = $(TCC) $(FLAGS) $(T2) $(ARGS)
87T2 = $(TCC) $(FLAGS) -run $< $(ARGS)96T2 = $(if $(NORUN),$1 -o a.exe && ./a.exe,-run $1)
88T3 = $(FILTER) >$*.output 2>&1 || true \97T3 = $(FILTER) >$*.output 2>&1 || true \
89 && diff -Nbu $(filter %.expect,$^) $*.output \98 && diff -Nbu $(filter %.expect,$^) $*.output \
90 && rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS))99 && rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS))
@@ -95,7 +104,7 @@ tests2.%+: · 4 unmodified lines
95 104
96# just run tcc to see the output, e.g. "make tests2.37-"105# just run tcc to see the output, e.g. "make tests2.37-"
97tests2.%-:106tests2.%-:
98 @$(MAKE) $(call F1,$*) NODIFF=true --no-print-directory107 @$(MAKE) $(call F1,$*) T3= --no-print-directory
99 108
100# run single test, e.g. "make tests2.37"109# run single test, e.g. "make tests2.37"
101tests2.%:110tests2.%:
@@ -111,9 +120,9 @@ F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)" · 9 unmodified lines
111 @rm -f *.exe *.obj *.pdb120 @rm -f *.exe *.obj *.pdb
112 121
113# using TCC for .expect if -dt in FLAGS122# using TCC for .expect if -dt in FLAGS
114GEN = $(if $(filter -dt,$(FLAGS)),$(GEN-TCC),$(GEN-CC))123GEN = $(if $(filter -dt -bt -b,$(FLAGS)),$(GEN-TCC),$(GEN-CC))
115GEN-CC = $(CC) -w -std=gnu99 $(FLAGS) $1 -o a.exe && ./a.exe $(ARGS)124GEN-CC = $(CC) -w -std=gnu99 $(FLAGS) $1 -o a.exe && ./a.exe $(ARGS)
116GEN-TCC = $(TCC) $(FLAGS) -run $1 $(ARGS)125GEN-TCC = $(T1)
117GEN-MSC = $(MS-CC) $1 && ./$(basename $@).exe126GEN-MSC = $(MS-CC) $1 && ./$(basename $@).exe
118MS-CC = cl127MS-CC = cl
119 128
@@ -124,5 +133,5 @@ MS-CC = cl · 4 unmodified lines
124$(sort $(GEN-ALWAYS) $(UPDATE)) : force133$(sort $(GEN-ALWAYS) $(UPDATE)) : force
125force:134force:
126 135
127clean:136clean tests2.clean :
128 rm -f fred.txt *.output a.exe $(GEN-ALWAYS)137 rm -f fred.txt *.output a.exe *.dll *.so *.def $(GEN-ALWAYS)
win32/build-tcc.bat+1−1
@@ -163,7 +163,7 @@ copy>nul tcc-win32.txt doc · 162 unmodified lines
163.\tcc -m64 -c ../lib/alloca86_64-bt.S163.\tcc -m64 -c ../lib/alloca86_64-bt.S
164.\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o164.\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o
165@if errorlevel 1 goto :the_end165@if errorlevel 1 goto :the_end
166.\tcc -m%T% -c ../lib/bcheck.c -o lib/bcheck.o166.\tcc -m%T% -c ../lib/bcheck.c -o lib/bcheck.o -g
167.\tcc -m%T% -c ../lib/bt-exe.c -o lib/bt-exe.o167.\tcc -m%T% -c ../lib/bt-exe.c -o lib/bt-exe.o
168.\tcc -m%T% -c ../lib/bt-log.c -o lib/bt-log.o168.\tcc -m%T% -c ../lib/bt-log.c -o lib/bt-log.o
169.\tcc -m%T% -c ../lib/bt-dll.c -o lib/bt-dll.o169.\tcc -m%T% -c ../lib/bt-dll.c -o lib/bt-dll.o
x86_64-gen.c+56−98
@@ -701,10 +701,57 @@ ST_FUNC void gen_bounded_ptr_deref(void) · 700 unmodified lines
701 rel = (ElfW(Rela) *)(cur_text_section->reloc->data + vtop->c.i);701 rel = (ElfW(Rela) *)(cur_text_section->reloc->data + vtop->c.i);
702 rel->r_info = ELF64_R_INFO(sym->c, ELF64_R_TYPE(rel->r_info));702 rel->r_info = ELF64_R_INFO(sym->c, ELF64_R_TYPE(rel->r_info));
703}703}
704
705#ifdef TCC_TARGET_PE
706# define TREG_FASTCALL_1 TREG_RCX
707#else
708# define TREG_FASTCALL_1 TREG_RDI
709#endif
710
711static void gen_bounds_prolog(void)
712{
713 /* leave some room for bound checking code */
714 func_bound_offset = lbounds_section->data_offset;
715 func_bound_ind = ind;
716 o(0xb848 + TREG_FASTCALL_1 * 0x100); /*lbound section pointer */
717 gen_le64 (0);
718 oad(0xb8, 0); /* call to function */
719}
720
721static void gen_bounds_epilog(void)
722{
723 addr_t saved_ind;
724 addr_t *bounds_ptr;
725 Sym *sym_data;
726
727 /* add end of table info */
728 bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
729 *bounds_ptr = 0;
730
731 /* generate bound local allocation */
732 sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
733 func_bound_offset, lbounds_section->data_offset);
734 saved_ind = ind;
735 ind = func_bound_ind;
736 greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
737 ind = ind + 10;
738 gen_bounds_call(TOK___bound_local_new);
739 ind = saved_ind;
740
741 /* generate bound check local freeing */
742 o(0x525051); /* save returned value, if any (+ scratch-space for windows) */
743 greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
744 o(0xb848 + TREG_FASTCALL_1 * 0x100); /* mov xxx, %rcx/di */
745 gen_le64 (0);
746 gen_bounds_call(TOK___bound_local_delete);
747 o(0x59585a); /* restore returned value, if any */
748}
704#endif749#endif
705 750
706#ifdef TCC_TARGET_PE751#ifdef TCC_TARGET_PE
707 752
753static int func_scratch, func_alloca;
754
708#define REGN 4755#define REGN 4
709static const uint8_t arg_regs[REGN] = {756static const uint8_t arg_regs[REGN] = {
710 TREG_RCX, TREG_RDX, TREG_R8, TREG_R9757 TREG_RCX, TREG_RDX, TREG_R8, TREG_R9
@@ -720,8 +767,6 @@ static int arg_prepare_reg(int idx) { · 9 unmodified lines
720 return arg_regs[idx];767 return arg_regs[idx];
721}768}
722 769
723static int func_scratch, func_alloca;
724
725/* Generate function call. The function address is pushed first, then770/* Generate function call. The function address is pushed first, then
726 all the parameters in call order. This functions pops all the771 all the parameters in call order. This functions pops all the
727 parameters and the function address. */772 parameters and the function address. */
@@ -918,7 +963,6 @@ void gfunc_prolog(Sym *func_sym) · 190 unmodified lines
918 int addr, reg_param_index, bt, size;963 int addr, reg_param_index, bt, size;
919 Sym *sym;964 Sym *sym;
920 CType *type;965 CType *type;
921 int n_arg = 0;
922 966
923 func_ret_sub = 0;967 func_ret_sub = 0;
924 func_scratch = 32;968 func_scratch = 32;
@@ -946,7 +990,6 @@ void gfunc_prolog(Sym *func_sym) · 21 unmodified lines
946 990
947 /* define parameters */991 /* define parameters */
948 while ((sym = sym->next) != NULL) {992 while ((sym = sym->next) != NULL) {
949 n_arg++;
950 type = &sym->type;993 type = &sym->type;
951 bt = type->t & VT_BTYPE;994 bt = type->t & VT_BTYPE;
952 size = gfunc_arg_size(type);995 size = gfunc_arg_size(type);
@@ -983,23 +1026,8 @@ void gfunc_prolog(Sym *func_sym) · 30 unmodified lines
983 reg_param_index++;1026 reg_param_index++;
984 }1027 }
985#ifdef CONFIG_TCC_BCHECK1028#ifdef CONFIG_TCC_BCHECK
986 /* leave some room for bound checking code */1029 if (tcc_state->do_bounds_check)
987 if (tcc_state->do_bounds_check) {1030 gen_bounds_prolog();
988 func_bound_offset = lbounds_section->data_offset;
989 func_bound_ind = ind;
990 o(0xb848); /* lbound section pointer */
991 gen_le64 (0);
992 o(0xc18948); /* mov %rax,%rcx ## first arg in %rdi, this must be ptr */
993 o(0x20ec8348); /* sub $20, %rsp */
994 oad(0xb8, 0); /* call to function */
995 o(0x20c48348); /* add $20, %rsp */
996 if (n_arg >= 2 && strcmp (get_tok_str(func_sym->v, NULL), "main") == 0) {
997 o(0x184d8b48); /* mov 0x18(%rbp),%rcx */
998 o(0x20ec8348); /* sub $20, %rsp */
999 gen_bounds_call(TOK___bound_main_arg);
1000 o(0x20c48348); /* add $20, %rsp */
1001 }
1002 }
1003#endif1031#endif
1004}1032}
1005 1033
@@ -1013,39 +1041,10 @@ void gfunc_epilog(void) · 7 unmodified lines
1013 loc = (loc & -16) - func_scratch;1041 loc = (loc & -16) - func_scratch;
1014 1042
1015#ifdef CONFIG_TCC_BCHECK1043#ifdef CONFIG_TCC_BCHECK
1016 if (tcc_state->do_bounds_check1044 if (tcc_state->do_bounds_check)
1017 && func_bound_offset != lbounds_section->data_offset)1045 gen_bounds_epilog();
1018 {
1019 addr_t saved_ind;
1020 addr_t *bounds_ptr;
1021 Sym *sym_data;
1022
1023 /* add end of table info */
1024 bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
1025 *bounds_ptr = 0;
1026
1027 /* generate bound local allocation */
1028 sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
1029 func_bound_offset, lbounds_section->data_offset);
1030 saved_ind = ind;
1031 ind = func_bound_ind;
1032 greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
1033 ind = ind + 10 + 3 + 4;
1034 gen_bounds_call(TOK___bound_local_new);
1035 ind = saved_ind;
1036
1037 /* generate bound check local freeing */
1038 o(0x5250); /* save returned value, if any */
1039 greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
1040 o(0xb848); /* mov xxx, %rax */
1041 gen_le64 (0);
1042 o(0xc18948); /* mov %rax,%rcx # first arg in %rdi, this must be ptr */
1043 o(0x20ec8348); /* sub $20, %rsp */
1044 gen_bounds_call(TOK___bound_local_delete);
1045 o(0x20c48348); /* add $20, %rsp */
1046 o(0x585a); /* restore returned value, if any */
1047 }
1048#endif1046#endif
1047
1049 o(0xc9); /* leave */1048 o(0xc9); /* leave */
1050 if (func_ret_sub == 0) {1049 if (func_ret_sub == 0) {
1051 o(0xc3); /* ret */1050 o(0xc3); /* ret */
@@ -1469,7 +1468,6 @@ void gfunc_prolog(Sym *func_sym) · 417 unmodified lines
1469 X86_64_Mode mode;1468 X86_64_Mode mode;
1470 int i, addr, align, size, reg_count;1469 int i, addr, align, size, reg_count;
1471 int param_addr = 0, reg_param_index, sse_param_index;1470 int param_addr = 0, reg_param_index, sse_param_index;
1472 int n_arg = 0;
1473 Sym *sym;1471 Sym *sym;
1474 CType *type;1472 CType *type;
1475 1473
@@ -1553,7 +1551,6 @@ void gfunc_prolog(Sym *func_sym) · 77 unmodified lines
1553 }1551 }
1554 /* define parameters */1552 /* define parameters */
1555 while ((sym = sym->next) != NULL) {1553 while ((sym = sym->next) != NULL) {
1556 n_arg++;
1557 type = &sym->type;1554 type = &sym->type;
1558 mode = classify_x86_64_arg(type, NULL, &size, &align, &reg_count);1555 mode = classify_x86_64_arg(type, NULL, &size, &align, &reg_count);
1559 switch (mode) {1556 switch (mode) {
@@ -1606,19 +1603,8 @@ void gfunc_prolog(Sym *func_sym) · 46 unmodified lines
1606 }1603 }
1607 1604
1608#ifdef CONFIG_TCC_BCHECK1605#ifdef CONFIG_TCC_BCHECK
1609 /* leave some room for bound checking code */1606 if (tcc_state->do_bounds_check)
1610 if (tcc_state->do_bounds_check) {1607 gen_bounds_prolog();
1611 func_bound_offset = lbounds_section->data_offset;
1612 func_bound_ind = ind;
1613 o(0xb848); /* lbound section pointer */
1614 gen_le64 (0);
1615 o(0xc78948); /* mov %rax,%rdi ## first arg in %rdi, this must be ptr */
1616 oad(0xb8, 0); /* call to function */
1617 if (n_arg >= 2 && strcmp (get_tok_str(func_sym->v, NULL), "main") == 0) {
1618 o(0xf07d8b48); /* mov -0x10(%rbp),%rdi */
1619 gen_bounds_call(TOK___bound_main_arg);
1620 }
1621 }
1622#endif1608#endif
1623}1609}
1624 1610
@@ -1628,36 +1614,8 @@ void gfunc_epilog(void) · 3 unmodified lines
1628 int v, saved_ind;1614 int v, saved_ind;
1629 1615
1630#ifdef CONFIG_TCC_BCHECK1616#ifdef CONFIG_TCC_BCHECK
1631 if (tcc_state->do_bounds_check1617 if (tcc_state->do_bounds_check)
1632 && func_bound_offset != lbounds_section->data_offset)1618 gen_bounds_epilog();
1633 {
1634 addr_t saved_ind;
1635 addr_t *bounds_ptr;
1636 Sym *sym_data;
1637
1638 /* add end of table info */
1639 bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
1640 *bounds_ptr = 0;
1641
1642 /* generate bound local allocation */
1643 sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
1644 func_bound_offset, lbounds_section->data_offset);
1645 saved_ind = ind;
1646 ind = func_bound_ind;
1647 greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
1648 ind = ind + 10 + 3;
1649 gen_bounds_call(TOK___bound_local_new);
1650 ind = saved_ind;
1651
1652 /* generate bound check local freeing */
1653 o(0x5250); /* save returned value, if any */
1654 greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
1655 o(0xb848); /* mov xxx, %rax */
1656 gen_le64 (0);
1657 o(0xc78948); /* mov %rax,%rdi # first arg in %rdi, this must be ptr */
1658 gen_bounds_call(TOK___bound_local_delete);
1659 o(0x585a); /* restore returned value, if any */
1660 }
1661#endif1619#endif
1662 o(0xc9); /* leave */1620 o(0xc9); /* leave */
1663 if (func_ret_sub == 0) {1621 if (func_ret_sub == 0) {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t