Skip to content

Commit

Permalink
RISCV64: Add support for 'bt -e' option
Browse files Browse the repository at this point in the history
With this patch we can search the stack for possible kernel and user
mode exception frames via 'bt -e' command.

TEST: a lkdtm DIRECT EXCEPTION vmcore

  crash> bt -e
  PID: 1        TASK: ff600000000e0000  CPU: 1    COMMAND: "sh"

  KERNEL-MODE EXCEPTION FRAME AT: ff200000000138d8
       PC: ffffffff805303c0  [lkdtm_EXCEPTION+6]
       RA: ffffffff8052fe36  [lkdtm_do_action+16]
       SP: ff20000000013cf0  CAUSE: 000000000000000f
  epc : ffffffff805303c0 ra : ffffffff8052fe36 sp : ff20000000013cf0
   gp : ffffffff814ef848 tp : ff600000000e0000 t0 : 6500000000000000
   t1 : 000000000000006c t2 : 6550203a6d74646b s0 : ff20000000013d00
   s1 : 000000000000000a a0 : ffffffff814aef40 a1 : c0000000ffffefff
   a2 : 0000000000000010 a3 : 0000000000000001 a4 : 5d53ea10ca096e00
   a5 : ffffffff805303ba a6 : 0000000000000008 a7 : 0000000000000038
   s2 : ff60000001324000 s3 : ffffffff814aef40 s4 : ff20000000013e30
   s5 : 000000000000000a s6 : ff20000000013e30 s7 : ff600000000ce000
   s8 : 0000555560f0f8a8 s9 : 00007ffff497f6b4 s10: 00007ffff497f6b0
   s11: 0000555560fa30e0 t3 : ffffffff81502197 t4 : ffffffff81502197
   t5 : ffffffff81502198 t6 : ff20000000013b28
   status: 0000000200000120 badaddr: 0000000000000000
    cause: 000000000000000f orig_a0: 0000000000000000

  USER-MODE EXCEPTION FRAME AT: ff20000000013ee0
       PC: 007fff8780431aff   RA: 007fff877b168400   SP: 007ffff497f5b000
       ORIG_A0: 0000000000000100   SYSCALLNO: 0000000000004000
  epc : 007fff8780431aff ra : 007fff877b168400 sp : 007ffff497f5b000
   gp : 00555560f5134800 tp : 007fff8774378000 t0 : 0000000000100000
   t1 : 00555560e427bc00 t2 : 0000000000271000 s0 : 007ffff497f5e000
   s1 : 0000000000000a00 a0 : 0000000000000100 a1 : 00555560faa68000
   a2 : 0000000000000a00 a3 : 4000000000000000 a4 : 20000000000000a8
   a5 : 0000000000000054 a6 : 0000000000000400 a7 : 0000000000004000
   s2 : 00555560faa68000 s3 : 007fff878b33f800 s4 : 0000000000000a00
   s5 : 00555560faa68000 s6 : 0000000000000a00 s7 : 00555560f5131400
   s8 : 00555560f0f8a800 s9 : 007ffff497f6b400 s10: 007ffff497f6b000
   s11: 00555560fa30e000 t3 : 007fff877af1fe00 t4 : 00555560fa6f2000
   t5 : 0000000000000100 t6 : 9e1fea5bf8683300
   status: 00000200004020b9 badaddr: 0000000000000000
    cause: 0000000000000800 orig_a0: 0000000000000100
  crash>

Signed-off-by: Song Shuai <[email protected]>
  • Loading branch information
Song Shuai authored and k-hagio committed Jan 11, 2024
1 parent edb2bd5 commit d86dc69
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 25 deletions.
15 changes: 8 additions & 7 deletions defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -7011,17 +7011,16 @@ int riscv64_IS_VMALLOC_ADDR(ulong);
#define display_idt_table() \
error(FATAL, "-d option is not applicable to RISCV64 architecture\n")

/* from arch/riscv/include/asm/ptrace.h */
/*
* regs[0,31] : struct user_regs_struct
* from arch/riscv/include/uapi/asm/ptrace.h
* regs[0,35] : struct pt_regs
* from arch/riscv/include/asm/ptrace.h
*/
struct riscv64_register {
ulong regs[36];
};

struct riscv64_pt_regs {
ulong badvaddr;
ulong cause;
ulong epc;
};

struct riscv64_unwind_frame {
ulong fp;
ulong sp;
Expand Down Expand Up @@ -7085,6 +7084,8 @@ struct machine_specific {
#define RISCV64_REGS_RA 1
#define RISCV64_REGS_SP 2
#define RISCV64_REGS_FP 8
#define RISCV64_REGS_STATUS 32
#define RISCV64_REGS_CAUSE 34

#endif /* RISCV64 */

Expand Down
191 changes: 173 additions & 18 deletions riscv64.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static int riscv64_kvtop(struct task_context *tc, ulong kvaddr,
static void riscv64_cmd_mach(void);
static void riscv64_stackframe_init(void);
static void riscv64_back_trace_cmd(struct bt_info *bt);
static int riscv64_eframe_search(struct bt_info *bt);
static int riscv64_get_dumpfile_stack_frame(struct bt_info *bt,
ulong *nip, ulong *ksp);
static void riscv64_get_stack_frame(struct bt_info *bt, ulong *pcp,
Expand All @@ -51,6 +52,8 @@ static int riscv64_get_elf_notes(void);
static void riscv64_get_va_range(struct machine_specific *ms);
static void riscv64_get_va_bits(struct machine_specific *ms);
static void riscv64_get_struct_page_size(struct machine_specific *ms);
static void riscv64_print_exception_frame(struct bt_info *, ulong , int );
static int riscv64_is_kernel_exception_frame(struct bt_info *, ulong );

#define REG_FMT "%016lx"
#define SZ_2G 0x80000000
Expand Down Expand Up @@ -210,6 +213,7 @@ riscv64_dump_machdep_table(ulong arg)
machdep->memsize, machdep->memsize);
fprintf(fp, " bits: %d\n", machdep->bits);
fprintf(fp, " back_trace: riscv64_back_trace_cmd()\n");
fprintf(fp, " eframe_search: riscv64_eframe_search()\n");
fprintf(fp, " processor_speed: riscv64_processor_speed()\n");
fprintf(fp, " uvtop: riscv64_uvtop()\n");
fprintf(fp, " kvtop: riscv64_kvtop()\n");
Expand Down Expand Up @@ -1398,6 +1402,7 @@ riscv64_init(int when)
machdep->cmd_mach = riscv64_cmd_mach;
machdep->get_stack_frame = riscv64_get_stack_frame;
machdep->back_trace = riscv64_back_trace_cmd;
machdep->eframe_search = riscv64_eframe_search;

machdep->vmalloc_start = riscv64_vmalloc_start;
machdep->processor_speed = riscv64_processor_speed;
Expand Down Expand Up @@ -1452,25 +1457,10 @@ riscv64_init(int when)
}
}

/*
* 'help -r' command output
*/
void
riscv64_display_regs_from_elf_notes(int cpu, FILE *ofp)
/* bool pt_regs : pass 1 to dump pt_regs , pass 0 to dump user_regs_struct */
static void
riscv64_dump_pt_regs(struct riscv64_register *regs, FILE *ofp, bool pt_regs)
{
const struct machine_specific *ms = machdep->machspec;
struct riscv64_register *regs;

if (!ms->crash_task_regs) {
error(INFO, "registers not collected for cpu %d\n", cpu);
return;
}

regs = &ms->crash_task_regs[cpu];
if (!regs->regs[RISCV64_REGS_SP] && !regs->regs[RISCV64_REGS_EPC]) {
error(INFO, "registers not collected for cpu %d\n", cpu);
return;
}

/* Print riscv64 32 regs */
fprintf(ofp,
Expand All @@ -1496,6 +1486,171 @@ riscv64_display_regs_from_elf_notes(int cpu, FILE *ofp)
regs->regs[24], regs->regs[25], regs->regs[26],
regs->regs[27], regs->regs[28], regs->regs[29],
regs->regs[30], regs->regs[31]);

if (pt_regs)
fprintf(ofp,
" status: " REG_FMT " badaddr: " REG_FMT "\n"
" cause: " REG_FMT " orig_a0: " REG_FMT "\n",
regs->regs[32], regs->regs[33], regs->regs[34],
regs->regs[35]);
}

/*
* 'help -r' command output
*/
void
riscv64_display_regs_from_elf_notes(int cpu, FILE *ofp)
{
const struct machine_specific *ms = machdep->machspec;
struct riscv64_register *regs;

if (!ms->crash_task_regs) {
error(INFO, "registers not collected for cpu %d\n", cpu);
return;
}

regs = &ms->crash_task_regs[cpu];
if (!regs->regs[RISCV64_REGS_SP] && !regs->regs[RISCV64_REGS_EPC]) {
error(INFO, "registers not collected for cpu %d\n", cpu);
return;
}

riscv64_dump_pt_regs(regs, ofp, 0);
}

#define USER_MODE (0)
#define KERNEL_MODE (1)

static void
riscv64_print_exception_frame(struct bt_info *bt, ulong ptr, int mode)
{

struct syment *sp;
ulong PC, RA, SP, offset;
struct riscv64_register *regs;

regs = (struct riscv64_register *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(ptr))];

PC = regs->regs[RISCV64_REGS_EPC];
RA = regs->regs[RISCV64_REGS_RA];
SP = regs->regs[RISCV64_REGS_SP];

switch (mode) {
case USER_MODE:
fprintf(fp,
" PC: %016lx RA: %016lx SP: %016lx\n"
" ORIG_A0: %016lx SYSCALLNO: %016lx\n",
PC, RA, SP, regs->regs[35], regs->regs[17]);

break;

case KERNEL_MODE:
fprintf(fp, " PC: %016lx ", PC);
if (is_kernel_text(PC) && (sp = value_search(PC, &offset))) {
fprintf(fp, "[%s", sp->name);
if (offset)
fprintf(fp, (*gdb_output_radix == 16) ?
"+0x%lx" : "+%ld", offset);
fprintf(fp, "]\n");
} else
fprintf(fp, "[unknown or invalid address]\n");

fprintf(fp, " RA: %016lx ", RA);
if (is_kernel_text(RA) && (sp = value_search(RA, &offset))) {
fprintf(fp, "[%s", sp->name);
if (offset)
fprintf(fp, (*gdb_output_radix == 16) ?
"+0x%lx" : "+%ld", offset);
fprintf(fp, "]\n");
} else
fprintf(fp, "[unknown or invalid address]\n");

fprintf(fp, " SP: %016lx CAUSE: %016lx\n",
SP, regs->regs[RISCV64_REGS_CAUSE]);

break;
}

riscv64_dump_pt_regs(regs, fp, 1);

}

static int
riscv64_is_kernel_exception_frame(struct bt_info *bt, ulong stkptr)
{
struct riscv64_register *regs;

if (stkptr > STACKSIZE() && !INSTACK(stkptr, bt)) {
if (CRASHDEBUG(1))
error(WARNING, "stkptr: %lx is outside the kernel stack range\n", stkptr);
return FALSE;
}

regs = (struct riscv64_register *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(stkptr))];

if (INSTACK(regs->regs[RISCV64_REGS_SP], bt) &&
INSTACK(regs->regs[RISCV64_REGS_FP], bt) &&
is_kernel_text(regs->regs[RISCV64_REGS_RA]) &&
is_kernel_text(regs->regs[RISCV64_REGS_EPC]) &&
((regs->regs[RISCV64_REGS_STATUS] >> 8) & 0x1) && // sstatus.SPP != 0
!((regs->regs[RISCV64_REGS_CAUSE] >> 63) & 0x1 ) && // scause.Interrupt != 1
!(regs->regs[RISCV64_REGS_CAUSE] == 0x00000008UL)) { // scause != ecall from U-mode

return TRUE;
}

return FALSE;
}

static int
riscv64_dump_kernel_eframes(struct bt_info *bt)
{
ulong ptr;
int count;

/*
* use old_regs to avoid the identical contiguous kernel exception frames
* created by Linux handle_exception() path ending at riscv_crash_save_regs()
*/
struct riscv64_register *regs, *old_regs;

count = 0;
old_regs = NULL;

for (ptr = bt->stackbase; ptr < bt->stacktop - SIZE(pt_regs); ptr++) {

regs = (struct riscv64_register *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(ptr))];

if (riscv64_is_kernel_exception_frame(bt, ptr)){
if (!old_regs || (old_regs &&
memcmp(old_regs, regs, sizeof(struct riscv64_register))) != 0){
old_regs = regs;
fprintf(fp, "\nKERNEL-MODE EXCEPTION FRAME AT: %lx\n", ptr);
riscv64_print_exception_frame(bt, ptr, KERNEL_MODE);
count++;
}
}
}

return count;
}

static int
riscv64_eframe_search(struct bt_info *bt)
{
ulong ptr;
int count;

count = riscv64_dump_kernel_eframes(bt);

if (is_kernel_thread(bt->tc->task))
return count;

ptr = bt->stacktop - SIZE(pt_regs);
fprintf(fp, "%sUSER-MODE EXCEPTION FRAME AT: %lx\n", count++ ? "\n" : "", ptr);
riscv64_print_exception_frame(bt, ptr, USER_MODE);

return count;
}

#else /* !RISCV64 */
Expand Down

0 comments on commit d86dc69

Please sign in to comment.