--- /dev/null
+#ifndef KERNEL_INCLUDE_STAB_h_
+#define KERNEL_INCLUDE_STAB_h_
+
+#include "types.h"
+
+// STABS debugging info
+
+// The XV6 kernel debugger can understand some debugging information
+// in the STABS format. For more information on this format, see
+// http://sourceware.org/gdb/onlinedocs/stabs.html
+
+// The constants below define some symbol types used by various debuggers
+// and compilers. XV6 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 {
+ uint n_strx; // index into string table of name
+ uchar n_type; // type of symbol
+ uchar n_other; // misc info (usually empty)
+ ushort n_desc; // description field
+ uint n_value; // value of symbol
+};
+
+// Debug information about a particular instruction pointer
+struct stab_info {
+ const char *eip_file; // Source code filename for EIP
+ int eip_line; // Source code linenumber for EIP
+
+ const char *eip_fn_name; // Name of function containing EIP
+ // - Note: not null terminated!
+ int eip_fn_namelen; // Length of function name
+ uint eip_fn_addr; // Address of start of function
+ int eip_fn_narg; // Number of function arguments
+};
+
+
+// Populates info to contain the stab_info about the given eip.
+// Returns 0 on success, non-zero on failure.
+int stab_info(uint eip, struct stab_info *info);
+
+#endif // KERNEL_INCLUDE_STAB_h_
+
--- /dev/null
+#ifndef KERNEL_INCLUDE_STRING_h_
+#define KERNEL_INCLUDE_STRING_h_
+
+#include "types.h"
+
+int strlen(const char *s);
+int strnlen(const char *s, size_t size);
+char *strcpy(char *dst, const char *src);
+//char * strncpy(char *dst, const char *src, size_t size);
+char *strcat(char *dst, const char *src);
+size_t strlcpy(char *dst, const char *src, size_t size);
+int strcmp(const char *s1, const char *s2);
+int strncmp(const char *s1, const char *s2, size_t size);
+char *strchr(const char *s, char c);
+char *strfind(const char *s, char c);
+
+void *memset(void *dst, int c, size_t len);
+void *memcpy(void *dst, const void *src, size_t len);
+void *memmove(void *dst, const void *src, size_t len);
+int memcmp(const void *s1, const void *s2, size_t len);
+void *memfind(const void *s, int c, size_t len);
+
+long strtol(const char *s, char **endptr, int base);
+
+char *safestrcpy(char *s, char *t, int n);
+char *strncpy(char *s, const char *t, int n);
+
+#endif // KERNEL_INCLUDE_STRING_h_
--- /dev/null
+#include "stab.h"
+#include "memlayout.h"
+#include "defs.h"
+#include "string.h"
+
+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
+
+
+// stab_binsearch(stabs, region_left, region_right, type, addr)
+//
+// 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.
+//
+/**
+ * @param stabs -- the stab array
+ * binsearh documentation
+ */
+static void
+stab_binsearch(const struct stab *stabs, int *region_left, int *region_right,
+ int type, uint 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'
+ for (l = *region_right;
+ l > *region_left && stabs[l].n_type != type;
+ l--)
+ /* do nothing */;
+ *region_left = l;
+ }
+}
+
+
+// stab_info(addr, info)
+//
+// 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
+stab_info(uint addr, struct stab_info *info)
+{
+ const struct stab *stabs, *stab_end;
+ const char *stabstr, *stabstr_end;
+ int lfile, rfile, lfun, rfun, lline, rline;
+
+ // Initialize *info
+ 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 {
+ // Can't search for user-level addresses yet!
+ panic("User address");
+ }
+
+ // 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).
+ 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).
+ lfun = lfile;
+ rfun = rfile;
+ 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;
+ }
+ // Ignore stuff after the colon.
+ 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 (rline < lline) {
+ return -1;
+ }
+ // line no is held in desc -- per the stab documentation (blerg)
+ info->eip_line = stabs[rline].n_desc;
+
+
+ // 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;
+}
+