Summary:

Exact behavior and corner cases: // - traceback() will be invoked only by single-threaded programs. // - you can assume that the largest function (in terms of number of bytes worth of instructions) is 1 megabyte (see traceback_internal.h) // - ensure that traceback() does not damage the correct operation of the program after it returns. // - assuming that the project that is calling it has a perfectly formed stack is not a good plan // - no executable code may lack a function-table entry, but return address might be corrupted // - traceback() must not cause a program calling it to crash / loop forever // - don't use fprintf() and printf() // - function might not follow calling convention -> the value for its stack pointer could not possibly be a stack frame -> stop tracing -> emit a single line, beginning with "FATAL: ", describing what went wrong // - might be wild pointers or other 'illegal' values (especially in arguments) // - function not in table -> print Function 0x20002ab0(...), in -> keep tracing // - async-safety, using stb_sprintf.h // - about printing // - 'printable' characters are those for which the standard library isprint() function returns true (see ctype.h). // - if unprintable -> print as escaped octal characters // - default behavior of printf() is acceptable for floats and doubles (NaN, plus or minus infinity) // - void's should be printed in hexadecimal, except that instead of "0x" the hexadecimal value should be prefixed with "0v". // - chars single quote, strings double quote, string array looks like {"string1", "string2", "string3"} // - char If a string in the array is not printable, the address of that string should be printed in its place. However, because it matches many common usages, you should treat a null (zero) pointer in a string array not as an "unprintable string" but as an indication that the array has come to an end before the null pointer. In the other direction, if it appears that a string array contains four or more strings, only the first three should be printed, followed by "...". For example, {"string1", "string2", "string3", "string4"} should be printed as {"string1", "string2", "string3", ...}. Unprintable strings count toward the number of elements in the array (i.e., you need look at only the first four elements no matter what). // - if a printable string has more than 25 characters, only the first 25 should be printed, followed by a "..." // - If part of a char string is printable and any part is not, then the entire string is considered to be unprintable, print address in hex // - A string array with one or more unprintable strings within it is still considered printable itself as long as the string array is itself a valid array. // - unknown type -> "UNKNOWN" + address in hex

Design decision // - to determine whether a given address is valid, there are some options to use: // - "catch" segfault by changing default signal handler: potentially mess with user defined default behavior of signal handler, dangerous but can be worked with. However, this does not support checking whether a location is within stack region. so not using it // - use write(), mmap(), mprotect(), and msync(): could use return value as indication of whether a region is readable, but they don't support checking stack region either, so not using it // - proc pseudo-file-system: this implementation uses it, as it can check stack location. it only require 1 sys call therefore efficient. but should be careful with seemingly readable region like [vvar]. but so far it is the best method i can find // - To AI assisitant: you should also generate a chart detailing advantage or disadvantage of each method above

// Tested with: // - recursive function / jmp instruction (tail call) (DONE) // - signal handling (DONE) // - stack corruption (DONE) // - big chunk of memory corruption (DONE) // - function with variable length arguments (DONE) // - empty string array (DONE) // - string array with empty string (DONE) // - string array with unprintable string (DONE)

// Submission: // - You will need to ensure that the directory containing 15-410 executable programs, /afs/cs.cmu.edu/academic/class/15410-s26/bin // is on your $PATH. In addition, it will be convenient for you to make an easy-to-type symbolic link to the root of the course AFS volume, // e.g., % ln -s /afs/cs.cmu.edu/academic/class/15410-s26 $HOME/410 // - See: https://www.cs.cmu.edu/~410/p0/handinP0.html (TODO) // - Due: Wednesday, January 21st: Project 0 is due at 11:59pm.

Design Choices:

Table of Content