7 #define STACKFRAME_DEPTH 20
8
9 extern const struct stab __STAB_BEGIN__[]; // beginning of stabs table
10 extern const struct stab __STAB_END__[]; // end of stabs table
11 extern const char __STABSTR_BEGIN__[]; // beginning of string table
12 extern const char __STABSTR_END__[]; // end of string table
13
14 /* debug information about a particular instruction pointer */
15 struct eipdebuginfo {
16 const char *eip_file; // source code filename for eip
17 int eip_line; // source code line number for eip
18 const char *eip_fn_name; // name of function containing eip
19 int eip_fn_namelen; // length of function's name
20 uintptr_t eip_fn_addr; // start address of function
21 int eip_fn_narg; // number of function arguments
22 };
9 /* Entries in the STABS table are formatted as follows. */
8 struct stab {
7 uint32_t n_strx; // index into string table of name
6 uint8_t n_type; // type of symbol
5 uint8_t n_other; // misc info (usually empty)
4 uint16_t n_desc; // description field
3 uintptr_t n_value; // value of symbol
2 };
66 static void
1 stab_binsearch(const struct stab *stabs, int *region_left, int *region_right,
2 int type, uintptr_t addr) {
3 int l = *region_left, r = *region_right, any_matches = 0;
4
5 while (l <= r) {
6 int true_m = (l + r) / 2, m = true_m;
7
8 // search for earliest stab with right type
9 // when fail at the end, l will become bigger than r.
10 // The logic here is simply to find the first m that suitable for our type.
11 while (m >= l && stabs[m].n_type != type) {
12 m --;
13 }
14 if (m < l) { // no match in [l, m]
15 l = true_m + 1;
16 continue;
17 }
18
19 // actual binary search
20 // For this while loop:
21 // 1. We assure the m is of right type. -> that will be computed for region_left or region_right.
22 // 2. We use binsearch to accelerate the speed to find m, we ensure at least one is smaller than addr,
23 // one is bigger than addr, but not ensure this m is the closest to the addr. When we are using binsearch,
24 // we implicitly omit some l and some r values. What we do here is simply found the right&left bounds.
25 any_matches = 1;
26 if (stabs[m].n_value < addr) {
27 *region_left = m;
28 l = true_m + 1;
29 } else if (stabs[m].n_value > addr) {
30 *region_right = m - 1;
31 r = m - 1;
32 } else {
33 // exact match for 'addr', but continue loop to find
34 // *region_right
35 *region_left = m;
36 l = m;
37 addr ++;
38 }
39 }
107 if (!any_matches) {
1 *region_right = *region_left - 1;
2 }
3 else {
4 // find rightmost region containing 'addr'
5 // Now we want to have a closer result.
6 l = *region_right;
7 for (; l > *region_left && stabs[l].n_type != type; l --)
8 /* do nothing */;
9 *region_left = l;
10 }
11 }
31 void
30 print_stackframe(void) {
29 /* LAB1 YOUR CODE : STEP 1 */
28 /* (1) call read_ebp() to get the value of ebp. the type is (uint32_t);
27 * (2) call read_eip() to get the value of eip. the type is (uint32_t);
26 * (3) from 0 .. STACKFRAME_DEPTH
25 * (3.1) printf value of ebp, eip
24 * (3.2) (uint32_t)calling arguments [0..4] = the contents in address (uint32_t)ebp +2 [0..4]
23 * (3.3) cprintf("\n");
22 * (3.4) call print_debuginfo(eip-1) to print the C calling function name and line number, etc.
21 * (3.5) popup a calling stackframe
20 * NOTICE: the calling funciton's return addr eip = ss:[ebp+4]
19 * the calling funciton's ebp = ss:[ebp]
18 */
17 int time = 0;
16 uint32_t ebp = read_ebp(); // | return address | <-- caller's eip. read_ebp will simply return ebp value.
15 // - - - - - - - - - -
14 uint32_t eip = read_eip(); // | last ebp | <-- ebp point to this position. read_eip will load the memory 4(%%ebp).
13 // BTW: the read_eip function here is very tricky!! Understand this thing is of great fun!
12
11 // End point: when ebp is equal to 0, then our stackframe chain ends.
10 while (ebp != 0 && time < STACKFRAME_DEPTH) {
9 cprintf("ebp:%08x eip:%08x ", ebp, eip);
8 uint32_t* args = (uint32_t*) ebp + 2;
7 cprintf("args:%08x %08x %08x %08x\n", args[0], args[1], args[2], args[3]);
6 // eip - 1 is sufficient for us to use binsearch to locate the line.
5 print_debuginfo(eip - 1);
4 eip = *((uint32_t*) ebp + 1);
3 ebp = *((uint32_t*) ebp);
2 time++;
1 }
331 }
/* idt_init - initialize IDT to each of the entry points in kern/trap/vectors.S */
4 void
5 idt_init(void) {
6 /* LAB1 YOUR CODE : STEP 2 */
7 /* (1) Where are the entry addrs of each Interrupt Service Routine (ISR)?
8 * All ISR's entry addrs are stored in __vectors. where is uintptr_t __vectors[] ?
9 * __vectors[] is in kern/trap/vector.S which is produced by tools/vector.c
10 * (try "make" command in lab1, then you will find vector.S in kern/trap DIR)
11 * You can use "extern uintptr_t __vectors[];" to define this extern variable which will be used later.
12 * (2) Now you should setup the entries of ISR in Interrupt Description Table (IDT).
13 * Can you see idt[256] in this file? Yes, it's IDT! you can use SETGATE macro to setup each item of IDT
14 * (3) After setup the contents of IDT, you will let CPU know where is the IDT by using 'lidt' instruction.
15 * You don't know the meaning of this instruction? just google it! and check the libs/x86.h to know more.
16 * Notice: the argument of lidt is idt_pd. try to find it!
17 */
18
19 // call extern global variabels __vectors.
20 extern uintptr_t __vectors[];
21
22 // use __vectors to initialize the idt entry.
23 for (int i = 0; i < 256; i++) {
24 SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], 0);
25 }
26
27 // lidt instruction to set the IDT with IDTR.
28 lidt(&idt_pd);
29 }