diff --git a/kernel/elf.c b/kernel/elf.c index beb3dffc78e37419e145574f1394303100289cb4..2f374b64ea72deb0a5ee7ee45a13f63a2abdb1bf 100644 --- a/kernel/elf.c +++ b/kernel/elf.c @@ -8,15 +8,23 @@ #include "riscv.h" #include "spike_interface/spike_utils.h" -typedef struct elf_info_t { +typedef struct elf_info_t +{ spike_file_t *f; process *p; } elf_info; +elf_symbol symbols[64]; +char sym_names[64][32]; +int sym_count; + +void load_func_name(elf_ctx *ctx); + // // the implementation of allocater. allocates memory space for later segment loading // -static void *elf_alloc_mb(elf_ctx *ctx, uint64 elf_pa, uint64 elf_va, uint64 size) { +static void *elf_alloc_mb(elf_ctx *ctx, uint64 elf_pa, uint64 elf_va, uint64 size) +{ // directly returns the virtual address as we are in the Bare mode in lab1_x return (void *)elf_va; } @@ -24,7 +32,8 @@ static void *elf_alloc_mb(elf_ctx *ctx, uint64 elf_pa, uint64 elf_va, uint64 siz // // actual file reading, using the spike file interface. // -static uint64 elf_fpread(elf_ctx *ctx, void *dest, uint64 nb, uint64 offset) { +static uint64 elf_fpread(elf_ctx *ctx, void *dest, uint64 nb, uint64 offset) +{ elf_info *msg = (elf_info *)ctx->info; // call spike file utility to load the content of elf file into memory. // spike_file_pread will read the elf file (msg->f) from offset to memory (indicated by @@ -35,14 +44,17 @@ static uint64 elf_fpread(elf_ctx *ctx, void *dest, uint64 nb, uint64 offset) { // // init elf_ctx, a data structure that loads the elf. // -elf_status elf_init(elf_ctx *ctx, void *info) { +elf_status elf_init(elf_ctx *ctx, void *info) +{ ctx->info = info; // load the elf header - if (elf_fpread(ctx, &ctx->ehdr, sizeof(ctx->ehdr), 0) != sizeof(ctx->ehdr)) return EL_EIO; + if (elf_fpread(ctx, &ctx->ehdr, sizeof(ctx->ehdr), 0) != sizeof(ctx->ehdr)) + return EL_EIO; // check the signature (magic value) of the elf - if (ctx->ehdr.magic != ELF_MAGIC) return EL_NOTELF; + if (ctx->ehdr.magic != ELF_MAGIC) + return EL_NOTELF; return EL_OK; } @@ -50,19 +62,25 @@ elf_status elf_init(elf_ctx *ctx, void *info) { // // load the elf segments to memory regions as we are in Bare mode in lab1 // -elf_status elf_load(elf_ctx *ctx) { +elf_status elf_load(elf_ctx *ctx) +{ // elf_prog_header structure is defined in kernel/elf.h elf_prog_header ph_addr; int i, off; // traverse the elf program segment headers - for (i = 0, off = ctx->ehdr.phoff; i < ctx->ehdr.phnum; i++, off += sizeof(ph_addr)) { + for (i = 0, off = ctx->ehdr.phoff; i < ctx->ehdr.phnum; i++, off += sizeof(ph_addr)) + { // read segment headers - if (elf_fpread(ctx, (void *)&ph_addr, sizeof(ph_addr), off) != sizeof(ph_addr)) return EL_EIO; + if (elf_fpread(ctx, (void *)&ph_addr, sizeof(ph_addr), off) != sizeof(ph_addr)) + return EL_EIO; - if (ph_addr.type != ELF_PROG_LOAD) continue; - if (ph_addr.memsz < ph_addr.filesz) return EL_ERR; - if (ph_addr.vaddr + ph_addr.memsz < ph_addr.vaddr) return EL_ERR; + if (ph_addr.type != ELF_PROG_LOAD) + continue; + if (ph_addr.memsz < ph_addr.filesz) + return EL_ERR; + if (ph_addr.vaddr + ph_addr.memsz < ph_addr.vaddr) + return EL_ERR; // allocate memory block before elf loading void *dest = elf_alloc_mb(ctx, ph_addr.vaddr, ph_addr.vaddr, ph_addr.memsz); @@ -75,7 +93,8 @@ elf_status elf_load(elf_ctx *ctx) { return EL_OK; } -typedef union { +typedef union +{ uint64 buf[MAX_CMDLINE_ARGS]; char *argv[MAX_CMDLINE_ARGS]; } arg_buf; @@ -84,36 +103,39 @@ typedef union { // returns the number (should be 1) of string(s) after PKE kernel in command line. // and store the string(s) in arg_bug_msg. // -static size_t parse_args(arg_buf *arg_bug_msg) { +static size_t parse_args(arg_buf *arg_bug_msg) +{ // HTIFSYS_getmainvars frontend call reads command arguments to (input) *arg_bug_msg long r = frontend_syscall(HTIFSYS_getmainvars, (uint64)arg_bug_msg, - sizeof(*arg_bug_msg), 0, 0, 0, 0, 0); + sizeof(*arg_bug_msg), 0, 0, 0, 0, 0); kassert(r == 0); size_t pk_argc = arg_bug_msg->buf[0]; uint64 *pk_argv = &arg_bug_msg->buf[1]; - int arg = 1; // skip the PKE OS kernel string, leave behind only the application name + int arg = 1; // skip the PKE OS kernel string, leave behind only the application name for (size_t i = 0; arg + i < pk_argc; i++) arg_bug_msg->argv[i] = (char *)(uintptr_t)pk_argv[arg + i]; - //returns the number of strings after PKE kernel in command line + // returns the number of strings after PKE kernel in command line return pk_argc - arg; } // // load the elf of user application, by using the spike file interface. // -void load_bincode_from_host_elf(process *p) { +void load_bincode_from_host_elf(process *p) +{ arg_buf arg_bug_msg; // retrieve command line arguements size_t argc = parse_args(&arg_bug_msg); - if (!argc) panic("You need to specify the application program!\n"); + if (!argc) + panic("You need to specify the application program!\n"); sprint("Application: %s\n", arg_bug_msg.argv[0]); - //elf loading. elf_ctx is defined in kernel/elf.h, used to track the loading process. + // elf loading. elf_ctx is defined in kernel/elf.h, used to track the loading process. elf_ctx elfloader; // elf_info is defined above, used to tie the elf file and its corresponding process. elf_info info; @@ -121,20 +143,73 @@ void load_bincode_from_host_elf(process *p) { info.f = spike_file_open(arg_bug_msg.argv[0], O_RDONLY, 0); info.p = p; // IS_ERR_VALUE is a macro defined in spike_interface/spike_htif.h - if (IS_ERR_VALUE(info.f)) panic("Fail on openning the input application program.\n"); + if (IS_ERR_VALUE(info.f)) + panic("Fail on openning the input application program.\n"); // init elfloader context. elf_init() is defined above. if (elf_init(&elfloader, &info) != EL_OK) panic("fail to init elfloader.\n"); // load elf. elf_load() is defined above. - if (elf_load(&elfloader) != EL_OK) panic("Fail on loading elf.\n"); + if (elf_load(&elfloader) != EL_OK) + panic("Fail on loading elf.\n"); // entry (virtual, also physical in lab1_x) address p->trapframe->epc = elfloader.ehdr.entry; + load_func_name(&elfloader); + // close the host spike file - spike_file_close( info.f ); + spike_file_close(info.f); sprint("Application program entry point (virtual address): 0x%lx\n", p->trapframe->epc); } + +void load_func_name(elf_ctx *ctx) +{ + elf_sect_header sym_sh; + elf_sect_header str_sh; + elf_sect_header shstr_sh; + elf_sect_header temp_sh; + + // 查找shstrtab + uint16 sect_num = ctx->ehdr.shnum; + uint64 shstr_offset = ctx->ehdr.shoff + ctx->ehdr.shstrndx * sizeof(elf_sect_header); + elf_fpread(ctx, (void *)&shstr_sh, sizeof(shstr_sh), shstr_offset); + + char temp_str[shstr_sh.sh_size]; + uint64 shstr_sect_off = shstr_sh.sh_offset; + elf_fpread(ctx, &temp_str, shstr_sh.sh_size, shstr_sect_off); + + // 查找strtab和symtab + for (int i = 0; i < sect_num; i++) + { + elf_fpread(ctx, (void *)&temp_sh, sizeof(temp_sh), ctx->ehdr.shoff + i * ctx->ehdr.shentsize); + uint32 type = temp_sh.sh_type; + if (type == SHT_SYMTAB) + { + sym_sh = temp_sh; + } + else if (type == SHT_STRTAB && strcmp(temp_str + temp_sh.sh_name, ".strtab") == 0) + { + str_sh = temp_sh; + } + } + + uint64 str_sect_off = str_sh.sh_offset; + uint64 sym_num = sym_sh.sh_size / sizeof(elf_symbol); + int count = 0; + for (int i = 0; i < sym_num; i++) + { + elf_symbol symbol; + elf_fpread(ctx, (void *)&symbol, sizeof(symbol), sym_sh.sh_offset + i * sizeof(elf_symbol)); + if (symbol.st_name != 0 && symbol.st_info == 18) + { + char sym_name[32]; + elf_fpread(ctx, (void *)&sym_name, sizeof(sym_name), str_sect_off + symbol.st_name); + symbols[count++] = symbol; + strcpy(sym_names[count - 1], sym_name); + } + } + sym_count = count; +} diff --git a/kernel/elf.h b/kernel/elf.h index 673c7d72a146a2b00495e3740e13e692db211cd8..bef1ce04222c49be8a5c1d00bf70d72e4de29f42 100644 --- a/kernel/elf.h +++ b/kernel/elf.h @@ -6,8 +6,37 @@ #define MAX_CMDLINE_ARGS 64 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define STT_FUNC 2 + +typedef struct elf_sect_header_t +{ + uint32 sh_name; /* Section name, index in string tbl */ + uint32 sh_type; /* Type of section */ + uint64 sh_flags; /* Miscellaneous section attributes */ + uint64 sh_addr; /* Section virtual addr at execution */ + uint64 sh_offset; /* Section file offset */ + uint64 sh_size; /* Size of section in bytes */ + uint32 sh_link; /* Index of another section */ + uint32 sh_info; /* Additional section information */ + uint64 sh_addralign; /* Section alignment */ + uint64 sh_entsize; /* Entry size if section holds table */ +} elf_sect_header; + +typedef struct elf64_sym +{ + uint32 st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + uint16 st_shndx; /* Associated section index */ + uint64 st_value; /* Value of the symbol */ + uint64 st_size; /* Associated symbol size */ +} elf_symbol; + // elf header structure -typedef struct elf_header_t { +typedef struct elf_header_t +{ uint32 magic; uint8 elf[12]; uint16 type; /* Object file type */ @@ -26,7 +55,8 @@ typedef struct elf_header_t { } elf_header; // Program segment header. -typedef struct elf_prog_header_t { +typedef struct elf_prog_header_t +{ uint32 type; /* Segment type */ uint32 flags; /* Segment flags */ uint64 off; /* Segment file offset */ @@ -37,10 +67,11 @@ typedef struct elf_prog_header_t { uint64 align; /* Segment alignment */ } elf_prog_header; -#define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian +#define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian #define ELF_PROG_LOAD 1 -typedef enum elf_status_t { +typedef enum elf_status_t +{ EL_OK = 0, EL_EIO, @@ -50,7 +81,8 @@ typedef enum elf_status_t { } elf_status; -typedef struct elf_ctx_t { +typedef struct elf_ctx_t +{ void *info; elf_header ehdr; } elf_ctx; @@ -60,4 +92,6 @@ elf_status elf_load(elf_ctx *ctx); void load_bincode_from_host_elf(process *p); +void elf_user_print_backtrace(uint64 depth); + #endif diff --git a/kernel/syscall.c b/kernel/syscall.c index 562245a09df3ca42c347320ff12c4316e11e219d..df58983f0393d461ad91ee408d258385c2525dc5 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -13,10 +13,17 @@ #include "spike_interface/spike_utils.h" +#include "elf.h" + +extern elf_symbol symbols[64]; +extern char sym_names[64][32]; +extern int sym_count; + // // implement the SYS_user_print syscall // -ssize_t sys_user_print(const char* buf, size_t n) { +ssize_t sys_user_print(const char *buf, size_t n) +{ sprint(buf); return 0; } @@ -24,24 +31,64 @@ ssize_t sys_user_print(const char* buf, size_t n) { // // implement the SYS_user_exit syscall // -ssize_t sys_user_exit(uint64 code) { +ssize_t sys_user_exit(uint64 code) +{ sprint("User exit with code:%d.\n", code); - // in lab1, PKE considers only one app (one process). + // in lab1, PKE considers only one app (one process). // therefore, shutdown the system when the app calls exit() shutdown(code); } +// ssize_t sys_user_print_backtrace(uint64 depth) { +// elf_user_print_backtrace(depth); +// return 0; +// } + +int func_name_printer(uint64 ret_addr) +{ + for (int i = 0; i < sym_count; i++) + { + if (ret_addr >= symbols[i].st_value && ret_addr < symbols[i].st_value + symbols[i].st_size) + { + sprint("%s\n", sym_names[i]); + if (strcmp(sym_names[i], "main") == 0) + return 0; + return 1; + } + } + return 1; +} + +ssize_t sys_user_print_backtrace(uint64 max_depth) +{ + uint64 sp = current->trapframe->regs.sp + 32; + uint64 ra = sp + 8; + uint64 depth = 0; + while (depth < max_depth) + { + if (func_name_printer(*(uint64 *)ra) == 0) + return depth; + ra += 16; + depth++; + } + return depth; +} + // // [a0]: the syscall number; [a1] ... [a7]: arguments to the syscalls. // returns the code of success, (e.g., 0 means success, fail for otherwise) // -long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) { - switch (a0) { - case SYS_user_print: - return sys_user_print((const char*)a1, a2); - case SYS_user_exit: - return sys_user_exit(a1); - default: - panic("Unknown syscall %ld \n", a0); +long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) +{ + switch (a0) + { + case SYS_user_print: + return sys_user_print((const char *)a1, a2); + case SYS_user_exit: + return sys_user_exit(a1); + case SYS_user_print_backtrace: + return sys_user_print_backtrace(a1); + default: + panic("Unknown syscall %ld \n", a0); } } diff --git a/kernel/syscall.h b/kernel/syscall.h index 9dd228c7b60e67f6f7f3df7b74ee68d03d3cec5e..b4492c0190e237121480d7176a1030e1d653ae8c 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -8,6 +8,7 @@ #define SYS_user_base 64 #define SYS_user_print (SYS_user_base + 0) #define SYS_user_exit (SYS_user_base + 1) +#define SYS_user_print_backtrace (SYS_user_base + 2) long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7); diff --git a/user/user_lib.c b/user/user_lib.c index fff4546d3753fc2d9d8133b08a4b5240cc9c13ec..f5daf91b495adc0a689061104be56260c4e26513 100644 --- a/user/user_lib.c +++ b/user/user_lib.c @@ -49,3 +49,7 @@ int printu(const char* s, ...) { int exit(int code) { return do_user_call(SYS_user_exit, code, 0, 0, 0, 0, 0, 0); } + +int print_backtrace(int max_depth) { + return do_user_call(SYS_user_print_backtrace, max_depth, 0, 0, 0, 0, 0, 0); +} diff --git a/user/user_lib.h b/user/user_lib.h index 7c538057a29ce38fdba9d34eb5c0504e85d1f05c..eed3f8c91f57e47b48515dcb430efc81e6420633 100644 --- a/user/user_lib.h +++ b/user/user_lib.h @@ -4,3 +4,5 @@ int printu(const char *s, ...); int exit(int code); + +int print_backtrace(int max_depth);