add lab answers
This commit is contained in:
27
labcodes_answer/lab8_result/kern/debug/assert.h
Normal file
27
labcodes_answer/lab8_result/kern/debug/assert.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef __KERN_DEBUG_ASSERT_H__
|
||||
#define __KERN_DEBUG_ASSERT_H__
|
||||
|
||||
#include <defs.h>
|
||||
|
||||
void __warn(const char *file, int line, const char *fmt, ...);
|
||||
void __noreturn __panic(const char *file, int line, const char *fmt, ...);
|
||||
|
||||
#define warn(...) \
|
||||
__warn(__FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
#define panic(...) \
|
||||
__panic(__FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
#define assert(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
panic("assertion failed: %s", #x); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// static_assert(x) will generate a compile-time error if 'x' is false.
|
||||
#define static_assert(x) \
|
||||
switch (x) { case 0: case (x): ; }
|
||||
|
||||
#endif /* !__KERN_DEBUG_ASSERT_H__ */
|
||||
|
||||
365
labcodes_answer/lab8_result/kern/debug/kdebug.c
Normal file
365
labcodes_answer/lab8_result/kern/debug/kdebug.c
Normal file
@@ -0,0 +1,365 @@
|
||||
#include <defs.h>
|
||||
#include <x86.h>
|
||||
#include <stab.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <memlayout.h>
|
||||
#include <sync.h>
|
||||
#include <vmm.h>
|
||||
#include <proc.h>
|
||||
#include <kdebug.h>
|
||||
#include <kmonitor.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define STACKFRAME_DEPTH 20
|
||||
|
||||
extern const struct stab __STAB_BEGIN__[]; // beginning of stabs table
|
||||
extern const struct stab __STAB_END__[]; // end of stabs table
|
||||
extern const char __STABSTR_BEGIN__[]; // beginning of string table
|
||||
extern const char __STABSTR_END__[]; // end of string table
|
||||
|
||||
/* debug information about a particular instruction pointer */
|
||||
struct eipdebuginfo {
|
||||
const char *eip_file; // source code filename for eip
|
||||
int eip_line; // source code line number for eip
|
||||
const char *eip_fn_name; // name of function containing eip
|
||||
int eip_fn_namelen; // length of function's name
|
||||
uintptr_t eip_fn_addr; // start address of function
|
||||
int eip_fn_narg; // number of function arguments
|
||||
};
|
||||
|
||||
/* user STABS data structure */
|
||||
struct userstabdata {
|
||||
const struct stab *stabs;
|
||||
const struct stab *stab_end;
|
||||
const char *stabstr;
|
||||
const char *stabstr_end;
|
||||
};
|
||||
|
||||
/* *
|
||||
* stab_binsearch - according to the input, the initial value of
|
||||
* range [*@region_left, *@region_right], find a single stab entry
|
||||
* that includes the address @addr and matches the type @type,
|
||||
* and then save its boundary to the locations that pointed
|
||||
* by @region_left and @region_right.
|
||||
*
|
||||
* Some stab types are arranged in increasing order by instruction address.
|
||||
* For example, N_FUN stabs (stab entries with n_type == N_FUN), which
|
||||
* mark functions, and N_SO stabs, which mark source files.
|
||||
*
|
||||
* Given an instruction address, this function finds the single stab entry
|
||||
* of type @type that contains that address.
|
||||
*
|
||||
* The search takes place within the range [*@region_left, *@region_right].
|
||||
* Thus, to search an entire set of N stabs, you might do:
|
||||
*
|
||||
* left = 0;
|
||||
* right = N - 1; (rightmost stab)
|
||||
* stab_binsearch(stabs, &left, &right, type, addr);
|
||||
*
|
||||
* The search modifies *region_left and *region_right to bracket the @addr.
|
||||
* *@region_left points to the matching stab that contains @addr,
|
||||
* and *@region_right points just before the next stab.
|
||||
* If *@region_left > *region_right, then @addr is not contained in any
|
||||
* matching stab.
|
||||
*
|
||||
* For example, given these N_SO stabs:
|
||||
* Index Type Address
|
||||
* 0 SO f0100000
|
||||
* 13 SO f0100040
|
||||
* 117 SO f0100176
|
||||
* 118 SO f0100178
|
||||
* 555 SO f0100652
|
||||
* 556 SO f0100654
|
||||
* 657 SO f0100849
|
||||
* this code:
|
||||
* left = 0, right = 657;
|
||||
* stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184);
|
||||
* will exit setting left = 118, right = 554.
|
||||
* */
|
||||
static void
|
||||
stab_binsearch(const struct stab *stabs, int *region_left, int *region_right,
|
||||
int type, uintptr_t addr) {
|
||||
int l = *region_left, r = *region_right, any_matches = 0;
|
||||
|
||||
while (l <= r) {
|
||||
int true_m = (l + r) / 2, m = true_m;
|
||||
|
||||
// search for earliest stab with right type
|
||||
while (m >= l && stabs[m].n_type != type) {
|
||||
m --;
|
||||
}
|
||||
if (m < l) { // no match in [l, m]
|
||||
l = true_m + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// actual binary search
|
||||
any_matches = 1;
|
||||
if (stabs[m].n_value < addr) {
|
||||
*region_left = m;
|
||||
l = true_m + 1;
|
||||
} else if (stabs[m].n_value > addr) {
|
||||
*region_right = m - 1;
|
||||
r = m - 1;
|
||||
} else {
|
||||
// exact match for 'addr', but continue loop to find
|
||||
// *region_right
|
||||
*region_left = m;
|
||||
l = m;
|
||||
addr ++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!any_matches) {
|
||||
*region_right = *region_left - 1;
|
||||
}
|
||||
else {
|
||||
// find rightmost region containing 'addr'
|
||||
l = *region_right;
|
||||
for (; l > *region_left && stabs[l].n_type != type; l --)
|
||||
/* do nothing */;
|
||||
*region_left = l;
|
||||
}
|
||||
}
|
||||
|
||||
/* *
|
||||
* debuginfo_eip - Fill in the @info structure with information about
|
||||
* the specified instruction address, @addr. Returns 0 if information
|
||||
* was found, and negative if not. But even if it returns negative it
|
||||
* has stored some information into '*info'.
|
||||
* */
|
||||
int
|
||||
debuginfo_eip(uintptr_t addr, struct eipdebuginfo *info) {
|
||||
const struct stab *stabs, *stab_end;
|
||||
const char *stabstr, *stabstr_end;
|
||||
|
||||
info->eip_file = "<unknown>";
|
||||
info->eip_line = 0;
|
||||
info->eip_fn_name = "<unknown>";
|
||||
info->eip_fn_namelen = 9;
|
||||
info->eip_fn_addr = addr;
|
||||
info->eip_fn_narg = 0;
|
||||
|
||||
// find the relevant set of stabs
|
||||
if (addr >= KERNBASE) {
|
||||
stabs = __STAB_BEGIN__;
|
||||
stab_end = __STAB_END__;
|
||||
stabstr = __STABSTR_BEGIN__;
|
||||
stabstr_end = __STABSTR_END__;
|
||||
}
|
||||
else {
|
||||
// user-program linker script, tools/user.ld puts the information about the
|
||||
// program's stabs (included __STAB_BEGIN__, __STAB_END__, __STABSTR_BEGIN__,
|
||||
// and __STABSTR_END__) in a structure located at virtual address USTAB.
|
||||
const struct userstabdata *usd = (struct userstabdata *)USTAB;
|
||||
|
||||
// make sure that debugger (current process) can access this memory
|
||||
struct mm_struct *mm;
|
||||
if (current == NULL || (mm = current->mm) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (!user_mem_check(mm, (uintptr_t)usd, sizeof(struct userstabdata), 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
stabs = usd->stabs;
|
||||
stab_end = usd->stab_end;
|
||||
stabstr = usd->stabstr;
|
||||
stabstr_end = usd->stabstr_end;
|
||||
|
||||
// make sure the STABS and string table memory is valid
|
||||
if (!user_mem_check(mm, (uintptr_t)stabs, (uintptr_t)stab_end - (uintptr_t)stabs, 0)) {
|
||||
return -1;
|
||||
}
|
||||
if (!user_mem_check(mm, (uintptr_t)stabstr, stabstr_end - stabstr, 0)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// String table validity checks
|
||||
if (stabstr_end <= stabstr || stabstr_end[-1] != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Now we find the right stabs that define the function containing
|
||||
// 'eip'. First, we find the basic source file containing 'eip'.
|
||||
// Then, we look in that source file for the function. Then we look
|
||||
// for the line number.
|
||||
|
||||
// Search the entire set of stabs for the source file (type N_SO).
|
||||
int lfile = 0, rfile = (stab_end - stabs) - 1;
|
||||
stab_binsearch(stabs, &lfile, &rfile, N_SO, addr);
|
||||
if (lfile == 0)
|
||||
return -1;
|
||||
|
||||
// Search within that file's stabs for the function definition
|
||||
// (N_FUN).
|
||||
int lfun = lfile, rfun = rfile;
|
||||
int lline, rline;
|
||||
stab_binsearch(stabs, &lfun, &rfun, N_FUN, addr);
|
||||
|
||||
if (lfun <= rfun) {
|
||||
// stabs[lfun] points to the function name
|
||||
// in the string table, but check bounds just in case.
|
||||
if (stabs[lfun].n_strx < stabstr_end - stabstr) {
|
||||
info->eip_fn_name = stabstr + stabs[lfun].n_strx;
|
||||
}
|
||||
info->eip_fn_addr = stabs[lfun].n_value;
|
||||
addr -= info->eip_fn_addr;
|
||||
// Search within the function definition for the line number.
|
||||
lline = lfun;
|
||||
rline = rfun;
|
||||
} else {
|
||||
// Couldn't find function stab! Maybe we're in an assembly
|
||||
// file. Search the whole file for the line number.
|
||||
info->eip_fn_addr = addr;
|
||||
lline = lfile;
|
||||
rline = rfile;
|
||||
}
|
||||
info->eip_fn_namelen = strfind(info->eip_fn_name, ':') - info->eip_fn_name;
|
||||
|
||||
// Search within [lline, rline] for the line number stab.
|
||||
// If found, set info->eip_line to the right line number.
|
||||
// If not found, return -1.
|
||||
stab_binsearch(stabs, &lline, &rline, N_SLINE, addr);
|
||||
if (lline <= rline) {
|
||||
info->eip_line = stabs[rline].n_desc;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Search backwards from the line number for the relevant filename stab.
|
||||
// We can't just use the "lfile" stab because inlined functions
|
||||
// can interpolate code from a different file!
|
||||
// Such included source files use the N_SOL stab type.
|
||||
while (lline >= lfile
|
||||
&& stabs[lline].n_type != N_SOL
|
||||
&& (stabs[lline].n_type != N_SO || !stabs[lline].n_value)) {
|
||||
lline --;
|
||||
}
|
||||
if (lline >= lfile && stabs[lline].n_strx < stabstr_end - stabstr) {
|
||||
info->eip_file = stabstr + stabs[lline].n_strx;
|
||||
}
|
||||
|
||||
// Set eip_fn_narg to the number of arguments taken by the function,
|
||||
// or 0 if there was no containing function.
|
||||
if (lfun < rfun) {
|
||||
for (lline = lfun + 1;
|
||||
lline < rfun && stabs[lline].n_type == N_PSYM;
|
||||
lline ++) {
|
||||
info->eip_fn_narg ++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* *
|
||||
* print_kerninfo - print the information about kernel, including the location
|
||||
* of kernel entry, the start addresses of data and text segements, the start
|
||||
* address of free memory and how many memory that kernel has used.
|
||||
* */
|
||||
void
|
||||
print_kerninfo(void) {
|
||||
extern char etext[], edata[], end[], kern_init[];
|
||||
cprintf("Special kernel symbols:\n");
|
||||
cprintf(" entry 0x%08x (phys)\n", kern_init);
|
||||
cprintf(" etext 0x%08x (phys)\n", etext);
|
||||
cprintf(" edata 0x%08x (phys)\n", edata);
|
||||
cprintf(" end 0x%08x (phys)\n", end);
|
||||
cprintf("Kernel executable memory footprint: %dKB\n", (end - kern_init + 1023)/1024);
|
||||
}
|
||||
|
||||
/* *
|
||||
* print_debuginfo - read and print the stat information for the address @eip,
|
||||
* and info.eip_fn_addr should be the first address of the related function.
|
||||
* */
|
||||
void
|
||||
print_debuginfo(uintptr_t eip) {
|
||||
struct eipdebuginfo info;
|
||||
if (debuginfo_eip(eip, &info) != 0) {
|
||||
cprintf(" <unknow>: -- 0x%08x --\n", eip);
|
||||
}
|
||||
else {
|
||||
char fnname[256];
|
||||
int j;
|
||||
for (j = 0; j < info.eip_fn_namelen; j ++) {
|
||||
fnname[j] = info.eip_fn_name[j];
|
||||
}
|
||||
fnname[j] = '\0';
|
||||
cprintf(" %s:%d: %s+%d\n", info.eip_file, info.eip_line,
|
||||
fnname, eip - info.eip_fn_addr);
|
||||
}
|
||||
}
|
||||
|
||||
static __noinline uint32_t
|
||||
read_eip(void) {
|
||||
uint32_t eip;
|
||||
asm volatile("movl 4(%%ebp), %0" : "=r" (eip));
|
||||
return eip;
|
||||
}
|
||||
|
||||
/* *
|
||||
* print_stackframe - print a list of the saved eip values from the nested 'call'
|
||||
* instructions that led to the current point of execution
|
||||
*
|
||||
* The x86 stack pointer, namely esp, points to the lowest location on the stack
|
||||
* that is currently in use. Everything below that location in stack is free. Pushing
|
||||
* a value onto the stack will invole decreasing the stack pointer and then writing
|
||||
* the value to the place that stack pointer pointes to. And popping a value do the
|
||||
* opposite.
|
||||
*
|
||||
* The ebp (base pointer) register, in contrast, is associated with the stack
|
||||
* primarily by software convention. On entry to a C function, the function's
|
||||
* prologue code normally saves the previous function's base pointer by pushing
|
||||
* it onto the stack, and then copies the current esp value into ebp for the duration
|
||||
* of the function. If all the functions in a program obey this convention,
|
||||
* then at any given point during the program's execution, it is possible to trace
|
||||
* back through the stack by following the chain of saved ebp pointers and determining
|
||||
* exactly what nested sequence of function calls caused this particular point in the
|
||||
* program to be reached. This capability can be particularly useful, for example,
|
||||
* when a particular function causes an assert failure or panic because bad arguments
|
||||
* were passed to it, but you aren't sure who passed the bad arguments. A stack
|
||||
* backtrace lets you find the offending function.
|
||||
*
|
||||
* The inline function read_ebp() can tell us the value of current ebp. And the
|
||||
* non-inline function read_eip() is useful, it can read the value of current eip,
|
||||
* since while calling this function, read_eip() can read the caller's eip from
|
||||
* stack easily.
|
||||
*
|
||||
* In print_debuginfo(), the function debuginfo_eip() can get enough information about
|
||||
* calling-chain. Finally print_stackframe() will trace and print them for debugging.
|
||||
*
|
||||
* Note that, the length of ebp-chain is limited. In boot/bootasm.S, before jumping
|
||||
* to the kernel entry, the value of ebp has been set to zero, that's the boundary.
|
||||
* */
|
||||
void
|
||||
print_stackframe(void) {
|
||||
/* LAB1 YOUR CODE : STEP 1 */
|
||||
/* (1) call read_ebp() to get the value of ebp. the type is (uint32_t);
|
||||
* (2) call read_eip() to get the value of eip. the type is (uint32_t);
|
||||
* (3) from 0 .. STACKFRAME_DEPTH
|
||||
* (3.1) printf value of ebp, eip
|
||||
* (3.2) (uint32_t)calling arguments [0..4] = the contents in address (unit32_t)ebp +2 [0..4]
|
||||
* (3.3) cprintf("\n");
|
||||
* (3.4) call print_debuginfo(eip-1) to print the C calling function name and line number, etc.
|
||||
* (3.5) popup a calling stackframe
|
||||
* NOTICE: the calling funciton's return addr eip = ss:[ebp+4]
|
||||
* the calling funciton's ebp = ss:[ebp]
|
||||
*/
|
||||
uint32_t ebp = read_ebp(), eip = read_eip();
|
||||
|
||||
int i, j;
|
||||
for (i = 0; ebp != 0 && i < STACKFRAME_DEPTH; i ++) {
|
||||
cprintf("ebp:0x%08x eip:0x%08x args:", ebp, eip);
|
||||
uint32_t *args = (uint32_t *)ebp + 2;
|
||||
for (j = 0; j < 4; j ++) {
|
||||
cprintf("0x%08x ", args[j]);
|
||||
}
|
||||
cprintf("\n");
|
||||
print_debuginfo(eip - 1);
|
||||
eip = ((uint32_t *)ebp)[1];
|
||||
ebp = ((uint32_t *)ebp)[0];
|
||||
}
|
||||
}
|
||||
|
||||
12
labcodes_answer/lab8_result/kern/debug/kdebug.h
Normal file
12
labcodes_answer/lab8_result/kern/debug/kdebug.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef __KERN_DEBUG_KDEBUG_H__
|
||||
#define __KERN_DEBUG_KDEBUG_H__
|
||||
|
||||
#include <defs.h>
|
||||
#include <trap.h>
|
||||
|
||||
void print_kerninfo(void);
|
||||
void print_stackframe(void);
|
||||
void print_debuginfo(uintptr_t eip);
|
||||
|
||||
#endif /* !__KERN_DEBUG_KDEBUG_H__ */
|
||||
|
||||
132
labcodes_answer/lab8_result/kern/debug/kmonitor.c
Normal file
132
labcodes_answer/lab8_result/kern/debug/kmonitor.c
Normal file
@@ -0,0 +1,132 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <mmu.h>
|
||||
#include <trap.h>
|
||||
#include <kmonitor.h>
|
||||
#include <kdebug.h>
|
||||
|
||||
/* *
|
||||
* Simple command-line kernel monitor useful for controlling the
|
||||
* kernel and exploring the system interactively.
|
||||
* */
|
||||
|
||||
struct command {
|
||||
const char *name;
|
||||
const char *desc;
|
||||
// return -1 to force monitor to exit
|
||||
int(*func)(int argc, char **argv, struct trapframe *tf);
|
||||
};
|
||||
|
||||
static struct command commands[] = {
|
||||
{"help", "Display this list of commands.", mon_help},
|
||||
{"kerninfo", "Display information about the kernel.", mon_kerninfo},
|
||||
{"backtrace", "Print backtrace of stack frame.", mon_backtrace},
|
||||
};
|
||||
|
||||
/* return if kernel is panic, in kern/debug/panic.c */
|
||||
bool is_kernel_panic(void);
|
||||
|
||||
#define NCOMMANDS (sizeof(commands)/sizeof(struct command))
|
||||
|
||||
/***** Kernel monitor command interpreter *****/
|
||||
|
||||
#define MAXARGS 16
|
||||
#define WHITESPACE " \t\n\r"
|
||||
|
||||
/* parse - parse the command buffer into whitespace-separated arguments */
|
||||
static int
|
||||
parse(char *buf, char **argv) {
|
||||
int argc = 0;
|
||||
while (1) {
|
||||
// find global whitespace
|
||||
while (*buf != '\0' && strchr(WHITESPACE, *buf) != NULL) {
|
||||
*buf ++ = '\0';
|
||||
}
|
||||
if (*buf == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
// save and scan past next arg
|
||||
if (argc == MAXARGS - 1) {
|
||||
cprintf("Too many arguments (max %d).\n", MAXARGS);
|
||||
}
|
||||
argv[argc ++] = buf;
|
||||
while (*buf != '\0' && strchr(WHITESPACE, *buf) == NULL) {
|
||||
buf ++;
|
||||
}
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
|
||||
/* *
|
||||
* runcmd - parse the input string, split it into separated arguments
|
||||
* and then lookup and invoke some related commands/
|
||||
* */
|
||||
static int
|
||||
runcmd(char *buf, struct trapframe *tf) {
|
||||
char *argv[MAXARGS];
|
||||
int argc = parse(buf, argv);
|
||||
if (argc == 0) {
|
||||
return 0;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < NCOMMANDS; i ++) {
|
||||
if (strcmp(commands[i].name, argv[0]) == 0) {
|
||||
return commands[i].func(argc - 1, argv + 1, tf);
|
||||
}
|
||||
}
|
||||
cprintf("Unknown command '%s'\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***** Implementations of basic kernel monitor commands *****/
|
||||
|
||||
void
|
||||
kmonitor(struct trapframe *tf) {
|
||||
cprintf("Welcome to the kernel debug monitor!!\n");
|
||||
cprintf("Type 'help' for a list of commands.\n");
|
||||
|
||||
if (tf != NULL) {
|
||||
print_trapframe(tf);
|
||||
}
|
||||
|
||||
char *buf;
|
||||
while (1) {
|
||||
if ((buf = readline("K> ")) != NULL) {
|
||||
if (runcmd(buf, tf) < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* mon_help - print the information about mon_* functions */
|
||||
int
|
||||
mon_help(int argc, char **argv, struct trapframe *tf) {
|
||||
int i;
|
||||
for (i = 0; i < NCOMMANDS; i ++) {
|
||||
cprintf("%s - %s\n", commands[i].name, commands[i].desc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* *
|
||||
* mon_kerninfo - call print_kerninfo in kern/debug/kdebug.c to
|
||||
* print the memory occupancy in kernel.
|
||||
* */
|
||||
int
|
||||
mon_kerninfo(int argc, char **argv, struct trapframe *tf) {
|
||||
print_kerninfo();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* *
|
||||
* mon_backtrace - call print_stackframe in kern/debug/kdebug.c to
|
||||
* print a backtrace of the stack.
|
||||
* */
|
||||
int
|
||||
mon_backtrace(int argc, char **argv, struct trapframe *tf) {
|
||||
print_stackframe();
|
||||
return 0;
|
||||
}
|
||||
|
||||
19
labcodes_answer/lab8_result/kern/debug/kmonitor.h
Normal file
19
labcodes_answer/lab8_result/kern/debug/kmonitor.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef __KERN_DEBUG_MONITOR_H__
|
||||
#define __KERN_DEBUG_MONITOR_H__
|
||||
|
||||
#include <trap.h>
|
||||
|
||||
void kmonitor(struct trapframe *tf);
|
||||
|
||||
int mon_help(int argc, char **argv, struct trapframe *tf);
|
||||
int mon_kerninfo(int argc, char **argv, struct trapframe *tf);
|
||||
int mon_backtrace(int argc, char **argv, struct trapframe *tf);
|
||||
int mon_continue(int argc, char **argv, struct trapframe *tf);
|
||||
int mon_step(int argc, char **argv, struct trapframe *tf);
|
||||
int mon_breakpoint(int argc, char **argv, struct trapframe *tf);
|
||||
int mon_watchpoint(int argc, char **argv, struct trapframe *tf);
|
||||
int mon_delete_dr(int argc, char **argv, struct trapframe *tf);
|
||||
int mon_list_dr(int argc, char **argv, struct trapframe *tf);
|
||||
|
||||
#endif /* !__KERN_DEBUG_MONITOR_H__ */
|
||||
|
||||
49
labcodes_answer/lab8_result/kern/debug/panic.c
Normal file
49
labcodes_answer/lab8_result/kern/debug/panic.c
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <defs.h>
|
||||
#include <stdio.h>
|
||||
#include <intr.h>
|
||||
#include <kmonitor.h>
|
||||
|
||||
static bool is_panic = 0;
|
||||
|
||||
/* *
|
||||
* __panic - __panic is called on unresolvable fatal errors. it prints
|
||||
* "panic: 'message'", and then enters the kernel monitor.
|
||||
* */
|
||||
void
|
||||
__panic(const char *file, int line, const char *fmt, ...) {
|
||||
if (is_panic) {
|
||||
goto panic_dead;
|
||||
}
|
||||
is_panic = 1;
|
||||
|
||||
// print the 'message'
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
cprintf("kernel panic at %s:%d:\n ", file, line);
|
||||
vcprintf(fmt, ap);
|
||||
cprintf("\n");
|
||||
va_end(ap);
|
||||
|
||||
panic_dead:
|
||||
intr_disable();
|
||||
while (1) {
|
||||
kmonitor(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* __warn - like panic, but don't */
|
||||
void
|
||||
__warn(const char *file, int line, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
cprintf("kernel warning at %s:%d:\n ", file, line);
|
||||
vcprintf(fmt, ap);
|
||||
cprintf("\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
bool
|
||||
is_kernel_panic(void) {
|
||||
return is_panic;
|
||||
}
|
||||
|
||||
54
labcodes_answer/lab8_result/kern/debug/stab.h
Normal file
54
labcodes_answer/lab8_result/kern/debug/stab.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef __KERN_DEBUG_STAB_H__
|
||||
#define __KERN_DEBUG_STAB_H__
|
||||
|
||||
#include <defs.h>
|
||||
|
||||
/* *
|
||||
* STABS debugging info
|
||||
*
|
||||
* The kernel debugger can understand some debugging information in
|
||||
* the STABS format. For more information on this format, see
|
||||
* http://sources.redhat.com/gdb/onlinedocs/stabs_toc.html
|
||||
*
|
||||
* The constants below define some symbol types used by various debuggers
|
||||
* and compilers. Kernel uses the N_SO, N_SOL, N_FUN, and N_SLINE types.
|
||||
* */
|
||||
|
||||
#define N_GSYM 0x20 // global symbol
|
||||
#define N_FNAME 0x22 // F77 function name
|
||||
#define N_FUN 0x24 // procedure name
|
||||
#define N_STSYM 0x26 // data segment variable
|
||||
#define N_LCSYM 0x28 // bss segment variable
|
||||
#define N_MAIN 0x2a // main function name
|
||||
#define N_PC 0x30 // global Pascal symbol
|
||||
#define N_RSYM 0x40 // register variable
|
||||
#define N_SLINE 0x44 // text segment line number
|
||||
#define N_DSLINE 0x46 // data segment line number
|
||||
#define N_BSLINE 0x48 // bss segment line number
|
||||
#define N_SSYM 0x60 // structure/union element
|
||||
#define N_SO 0x64 // main source file name
|
||||
#define N_LSYM 0x80 // stack variable
|
||||
#define N_BINCL 0x82 // include file beginning
|
||||
#define N_SOL 0x84 // included source file name
|
||||
#define N_PSYM 0xa0 // parameter variable
|
||||
#define N_EINCL 0xa2 // include file end
|
||||
#define N_ENTRY 0xa4 // alternate entry point
|
||||
#define N_LBRAC 0xc0 // left bracket
|
||||
#define N_EXCL 0xc2 // deleted include file
|
||||
#define N_RBRAC 0xe0 // right bracket
|
||||
#define N_BCOMM 0xe2 // begin common
|
||||
#define N_ECOMM 0xe4 // end common
|
||||
#define N_ECOML 0xe8 // end common (local name)
|
||||
#define N_LENG 0xfe // length of preceding entry
|
||||
|
||||
/* Entries in the STABS table are formatted as follows. */
|
||||
struct stab {
|
||||
uint32_t n_strx; // index into string table of name
|
||||
uint8_t n_type; // type of symbol
|
||||
uint8_t n_other; // misc info (usually empty)
|
||||
uint16_t n_desc; // description field
|
||||
uintptr_t n_value; // value of symbol
|
||||
};
|
||||
|
||||
#endif /* !__KERN_DEBUG_STAB_H__ */
|
||||
|
||||
Reference in New Issue
Block a user