diff --git a/LICENSE.txt b/LICENSE.txt index b586e63..a9e75e7 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -4,8 +4,9 @@ Copyright License The PKE software is: Copyright (c) 2021, Zhiyuan Shao (zyshao@hust.edu.cn), - Yi Gui (gy163email@163.com), - Yan Jiao (773709579@qq.com), + Ziming Yuan (1223962053@qq.com), + Yixin Song (yixinsong@hust.edu.cn), + Boyang Li (liboyang_hust@163.com), Huazhong University of Science and Technology Permission is hereby granted, free of charge, to any person obtaining diff --git a/Makefile b/Makefile index 5ed973d..bb289a4 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ USER_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_CPPS))) -USER_TARGET := $(OBJ_DIR)/app_long_loop +USER_TARGET := $(OBJ_DIR)/app_errorline #------------------------targets------------------------ $(OBJ_DIR): @-mkdir -p $(OBJ_DIR) diff --git a/kernel/elf.c b/kernel/elf.c index 666229f..51c2649 100644 --- a/kernel/elf.c +++ b/kernel/elf.c @@ -44,7 +44,151 @@ elf_status elf_init(elf_ctx *ctx, void *info) { return EL_OK; } - +// leb128 (little-endian base 128) is a variable-length +// compression algoritm in DWARF +void read_uleb128(uint64 *out, char **off) { + uint64 value = 0; int shift = 0; uint8 b; + for (;;) { + b = *(uint8 *)(*off); (*off)++; + value |= ((uint64)b & 0x7F) << shift; + shift += 7; + if ((b & 0x80) == 0) break; + } + if (out) *out = value; +} +void read_sleb128(int64 *out, char **off) { + int64 value = 0; int shift = 0; uint8 b; + for (;;) { + b = *(uint8 *)(*off); (*off)++; + value |= ((uint64_t)b & 0x7F) << shift; + shift += 7; + if ((b & 0x80) == 0) break; + } + if (shift < 64 && (b & 0x40)) value |= -(1 << shift); + if (out) *out = value; +} +// Since reading below types through pointer cast requires aligned address, +// so we can only read them byte by byte +void read_uint64(uint64 *out, char **off) { + *out = 0; + for (int i = 0; i < 8; i++) { + *out |= (uint64)(**off) << (i << 3); (*off)++; + } +} +void read_uint32(uint32 *out, char **off) { + *out = 0; + for (int i = 0; i < 4; i++) { + *out |= (uint32)(**off) << (i << 3); (*off)++; + } +} +void read_uint16(uint16 *out, char **off) { + *out = 0; + for (int i = 0; i < 2; i++) { + *out |= (uint16)(**off) << (i << 3); (*off)++; + } +} +/* +* analyzis the data in the debug_line section +* +* the function needs 3 parameters: elf context, data in the debug_line section +* and length of debug_line section +* +* make 3 arrays: +* "process->dir" stores all directory paths of code files +* "process->file" stores all code file names of code files and their directory path index of array "dir" +* "process->line" stores all relationships map instruction addresses to code line numbers +* and their code file name index of array "file" +*/ +void make_addr_line(elf_ctx *ctx, char *debug_line, uint64 length) { + process *p = ((elf_info *)ctx->info)->p; + p->debugline = debug_line; + // directory name char pointer array + p->dir = (char **)((((uint64)debug_line + length + 7) >> 3) << 3); int dir_ind = 0, dir_base; + // file name char pointer array + p->file = (code_file *)(p->dir + 64); int file_ind = 0, file_base; + // table array + p->line = (addr_line *)(p->file + 64); p->line_ind = 0; + char *off = debug_line; + while (off < debug_line + length) { // iterate each compilation unit(CU) + debug_header *dh = (debug_header *)off; off += sizeof(debug_header); + dir_base = dir_ind; file_base = file_ind; + // get directory name char pointer in this CU + while (*off != 0) { + p->dir[dir_ind++] = off; while (*off != 0) off++; off++; + } + off++; + // get file name char pointer in this CU + while (*off != 0) { + p->file[file_ind].file = off; while (*off != 0) off++; off++; + uint64 dir; read_uleb128(&dir, &off); + p->file[file_ind++].dir = dir - 1 + dir_base; + read_uleb128(NULL, &off); read_uleb128(NULL, &off); + } + off++; addr_line regs; regs.addr = 0; regs.file = 1; regs.line = 1; + // simulate the state machine op code + for (;;) { + uint8 op = *(off++); + switch (op) { + case 0: // Extended Opcodes + read_uleb128(NULL, &off); op = *(off++); + switch (op) { + case 1: // DW_LNE_end_sequence + if (p->line_ind > 0 && p->line[p->line_ind - 1].addr == regs.addr) p->line_ind--; + p->line[p->line_ind] = regs; p->line[p->line_ind].file += file_base - 1; + p->line_ind++; goto endop; + case 2: // DW_LNE_set_address + read_uint64(®s.addr, &off); break; + // ignore DW_LNE_define_file + case 4: // DW_LNE_set_discriminator + read_uleb128(NULL, &off); break; + } + break; + case 1: // DW_LNS_copy + if (p->line_ind > 0 && p->line[p->line_ind - 1].addr == regs.addr) p->line_ind--; + p->line[p->line_ind] = regs; p->line[p->line_ind].file += file_base - 1; + p->line_ind++; break; + case 2: { // DW_LNS_advance_pc + uint64 delta; read_uleb128(&delta, &off); + regs.addr += delta * dh->min_instruction_length; + break; + } + case 3: { // DW_LNS_advance_line + int64 delta; read_sleb128(&delta, &off); + regs.line += delta; break; } case 4: // DW_LNS_set_file + read_uleb128(®s.file, &off); break; + case 5: // DW_LNS_set_column + read_uleb128(NULL, &off); break; + case 6: // DW_LNS_negate_stmt + case 7: // DW_LNS_set_basic_block + break; + case 8: { // DW_LNS_const_add_pc + int adjust = 255 - dh->opcode_base; + int delta = (adjust / dh->line_range) * dh->min_instruction_length; + regs.addr += delta; break; + } + case 9: { // DW_LNS_fixed_advanced_pc + uint16 delta; read_uint16(&delta, &off); + regs.addr += delta; + break; + } + // ignore 10, 11 and 12 + default: { // Special Opcodes + int adjust = op - dh->opcode_base; + int addr_delta = (adjust / dh->line_range) * dh->min_instruction_length; + int line_delta = dh->line_base + (adjust % dh->line_range); + regs.addr += addr_delta; + regs.line += line_delta; + if (p->line_ind > 0 && p->line[p->line_ind - 1].addr == regs.addr) p->line_ind--; + p->line[p->line_ind] = regs; p->line[p->line_ind].file += file_base - 1; + p->line_ind++; break; + } + } + } +endop:; + } + // for (int i = 0; i < p->line_ind; i++) + // sprint("%p %d %d\n", p->line[i].addr, p->line[i].line, p->line[i].file); +} // // load the elf segments to memory regions as we are in Bare mode in lab1 // diff --git a/kernel/elf.h b/kernel/elf.h index 673c7d7..3f1b2cb 100644 --- a/kernel/elf.h +++ b/kernel/elf.h @@ -37,6 +37,33 @@ typedef struct elf_prog_header_t { uint64 align; /* Segment alignment */ } elf_prog_header; +// elf section header +typedef struct elf_sect_header_t{ + uint32 name; + uint32 type; + uint64 flags; + uint64 addr; + uint64 offset; + uint64 size; + uint32 link; + uint32 info; + uint64 addralign; + uint64 entsize; +} elf_sect_header; + +// compilation units header (in debug line section) +typedef struct __attribute__((packed)) { + uint32 length; + uint16 version; + uint32 header_length; + uint8 min_instruction_length; + uint8 default_is_stmt; + int8 line_base; + uint8 line_range; + uint8 opcode_base; + uint8 std_opcode_lengths[12]; +} debug_header; + #define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian #define ELF_PROG_LOAD 1 diff --git a/kernel/process.h b/kernel/process.h index 594b1f2..94d5245 100644 --- a/kernel/process.h +++ b/kernel/process.h @@ -15,12 +15,22 @@ typedef struct trapframe { /* offset:264 */ uint64 epc; }trapframe; +// code file struct, including directory index and file name char pointer +typedef struct { + uint64 dir; char *file; +} code_file; +// address-line number-file name table +typedef struct { + uint64 addr, line, file; +} addr_line; + // the extremely simple definition of process, used for begining labs of PKE typedef struct process { // pointing to the stack used in trap handling. uint64 kstack; // trapframe storing the context of a (User mode) process. trapframe* trapframe; + char *debugline; char **dir; code_file *file; addr_line *line; int line_ind; }process; void switch_to(process*); diff --git a/user/app_errorline.c b/user/app_errorline.c new file mode 100644 index 0000000..223ccf8 --- /dev/null +++ b/user/app_errorline.c @@ -0,0 +1,16 @@ +/* + * Below is the given application for lab1_challenge2 (same as lab1_2). + * This app attempts to issue M-mode instruction in U-mode, and consequently raises an exception. + */ + +#include "user_lib.h" +#include "util/types.h" + +int main(void) { + printu("Going to hack the system by running privilege instructions.\n"); + // we are now in U(user)-mode, but the "csrw" instruction requires M-mode privilege. + // Attempting to execute such instruction will raise illegal instruction exception. + asm volatile("csrw sscratch, 0"); + exit(0); +} + diff --git a/user/app_long_loop.c b/user/app_long_loop.c deleted file mode 100644 index 8b4d873..0000000 --- a/user/app_long_loop.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Below is the given application for lab1_3. - * This app performs a long loop, during which, timers are - * generated and pop messages to our screen. - */ - -#include "user_lib.h" -#include "util/types.h" - -int main(void) { - printu("Hello world!\n"); - int i; - for (i = 0; i < 100000000; ++i) { - if (i % 5000000 == 0) printu("wait %d\n", i); - } - - exit(0); - - return 0; -}