Ejemplo n.º 1
0
void printStackTrace(std::ostream& out) {
    // constructing the following object jumps into fancy code in call_stack_gcc/windows.cpp
    // to rebuild the stack trace; implementation differs for each operating system
    stacktrace::call_stack trace;
    std::vector<stacktrace::entry> entries = trace.stack;
    
    // get longest line string length to line up stack traces
    void* fakeStackPtr = stacktrace::getFakeCallStackPointer();
    int entriesToShowCount = 0;
    int funcNameLength = 0;
    int lineStrLength = 0;
    for (size_t i = 0; i < entries.size(); ++i) {
        // remove references to std:: namespace
        stringReplaceInPlace(entries[i].function, "std::", "");
        
        // a few substitutions related to predefined types for simplicity
        stringReplaceInPlace(entries[i].function, "basic_ostream", "ostream");
        stringReplaceInPlace(entries[i].function, "basic_istream", "istream");
        stringReplaceInPlace(entries[i].function, "basic_ofstream", "ofstream");
        stringReplaceInPlace(entries[i].function, "basic_ifstream", "ifstream");
        stringReplaceInPlace(entries[i].function, "basic_string", "string");
        
        // remove template arguments
        // TODO: does not work well for nested templates
        int lessThan = stringIndexOf(entries[i].function, "<");
        while (lessThan >= 0) {
            // see if there is a matching > for this <
            int greaterThan = lessThan + 1;
            int count = 1;
            while (greaterThan < (int) entries[i].function.length()) {
                if (entries[i].function[greaterThan] == '<') {
                    count++;
                } else if (entries[i].function[greaterThan] == '>') {
                    count--;
                    if (count == 0) {
                        break;
                    }
                }
                greaterThan++;
            }
            if (count == 0 && lessThan >= 0 && greaterThan > lessThan) {
                entries[i].function.erase(lessThan, greaterThan - lessThan + 1);
            } else {
                // look for the next < in the string, if any, to see if it has a matching >
                lessThan = stringIndexOf(entries[i].function, "<", lessThan + 1);
            }
        }
        
        if (!STACK_TRACE_SHOULD_FILTER || !shouldFilterOutFromStackTrace(entries[i].function)) {
            lineStrLength = std::max(lineStrLength, (int) entries[i].lineStr.length());
            funcNameLength = std::max(funcNameLength, (int) entries[i].function.length());
            entriesToShowCount++;
        }
    }
    
    if (entries.empty() || entriesToShowCount == 0) {
        out << " *** No useful stack trace available." << std::endl;
        out << " ***" << std::endl;
        return;
    }
    
    if (lineStrLength > 0) {
        out << " *** Stack trace (line numbers are approximate):" << std::endl;
        if (STACK_TRACE_SHOW_TOP_BOTTOM_BARS) {
            out << " *** "
                      << std::setw(lineStrLength) << std::left
                      << "file:line" << "  " << "function" << std::endl;
            out << " *** "
                      << std::string(lineStrLength + 2 + funcNameLength, '=') << std::endl;
        }
    } else {
        out << " *** Stack trace:" << std::endl;
    }
    
    for (size_t i = 0; i < entries.size(); ++i) {
        stacktrace::entry entry = entries[i];
        entry.file = getTail(entry.file);
        
        // skip certain entries for clarity
        if (STACK_TRACE_SHOULD_FILTER && shouldFilterOutFromStackTrace(entry.function)) {
            continue;
        }
        
        // show Main() as main() to hide hidden case-change by Stanford C++ lib internals
        if (startsWith(entry.function, "Main(")) {
            entry.function.replace(0, 5, "main(");
        }
        
        std::string lineStr = "";
        if (!entry.lineStr.empty()) {
            lineStr = entry.lineStr;
            if (lineStr == "?? ??:0") {
                lineStr = "(unknown)";
            }
        } else if (entry.line > 0) {
            lineStr = "line " + integerToString(entry.line);
        }


        // JL debugging
//        cout << "entry #" << i << endl;
//        cout << "lineStrLength: " << lineStrLength << endl;
//        cout << "lineStr: " << lineStr << endl;
//        cout << "entry.function: " << entry.function << endl;
        // JL end debugging


        out << " *** " << std::left << std::setw(lineStrLength) << lineStr
                  << "  " << entry.function << std::endl;
        
        // don't show entries beneath the student's main() function, for simplicity
        if (entry.function == "main()") {
            break;
        }
    }
    if (entries.size() == 1 && entries[0].address == fakeStackPtr) {
        out << " *** (partial stack due to crash)" << std::endl;
    }

    if (STACK_TRACE_SHOW_TOP_BOTTOM_BARS && lineStrLength > 0) {
        out << " *** "
                  << std::string(lineStrLength + 2 + funcNameLength, '=') << std::endl;
    }
    
    out << " ***" << std::endl;
    out << " *** NOTE:" << std::endl;
    out << " *** Any line numbers listed above are approximate." << std::endl;
    out << " *** To learn more about why the program crashed, we" << std::endl;
    out << " *** suggest running your program under the debugger." << std::endl;
    
    out << " ***" << std::endl;
}
void printStackTrace(std::ostream& out) {
    // constructing the following object jumps into fancy code in call_stack_gcc/windows.cpp
    // to rebuild the stack trace; implementation differs for each operating system
    stacktrace::call_stack trace;
    std::vector<stacktrace::entry> entries = trace.stack;
    
    // get longest line string length to line up stack traces
    void* fakeStackPtr = stacktrace::getFakeCallStackPointer();
    int entriesToShowCount = 0;
    int funcNameLength = 0;
    int lineStrLength = 0;
    for (size_t i = 0; i < entries.size(); ++i) {
        // remove references to std:: namespace
        stringReplaceInPlace(entries[i].function, "std::", "");
        
        // remove template arguments
        while (stringContains(entries[i].function, "<") && stringContains(entries[i].function, ">")) {
            int lessThan = stringIndexOf(entries[i].function, "<");
            int greaterThan = stringIndexOf(entries[i].function, ">", lessThan);
            if (lessThan >= 0 && greaterThan > lessThan) {
                entries[i].function.erase(lessThan, greaterThan - lessThan + 1);
            }
        }
        
        if (!STACK_TRACE_SHOULD_FILTER || !shouldFilterOutFromStackTrace(entries[i].function)) {
            lineStrLength = std::max(lineStrLength, (int) entries[i].lineStr.length());
            funcNameLength = std::max(funcNameLength, (int) entries[i].function.length());
            entriesToShowCount++;
        }
    }
    
    if (entries.empty() || entriesToShowCount == 0) {
        return;   // couldn't get a stack trace, or had no useful data  :-(
    }
    
    if (lineStrLength > 0) {
        out << " *** Stack trace (line numbers are approximate):" << std::endl;
        if (STACK_TRACE_SHOW_TOP_BOTTOM_BARS) {
            out << " *** "
                      << std::setw(lineStrLength) << std::left
                      << "file:line" << "  " << "function" << std::endl;
            out << " *** "
                      << std::string(lineStrLength + 2 + funcNameLength, '=') << std::endl;
        }
    } else {
        out << " *** Stack trace:" << std::endl;
    }
    
    for (size_t i = 0; i < entries.size(); ++i) {
        stacktrace::entry entry = entries[i];
        entry.file = getTail(entry.file);
        
        // skip certain entries for clarity
        if (STACK_TRACE_SHOULD_FILTER && shouldFilterOutFromStackTrace(entry.function)) {
            continue;
        }
        
        // show Main() as main() to hide hidden case-change by Stanford C++ lib internals
        if (startsWith(entry.function, "Main(")) {
            entry.function.replace(0, 5, "main(");
        }
        
        std::string lineStr = "";
        if (!entry.lineStr.empty()) {
            lineStr = entry.lineStr;
        } else if (entry.line > 0) {
            lineStr = "line " + integerToString(entry.line);
        }
        
        out << " *** " << std::left << std::setw(lineStrLength) << lineStr
                  << "  " << entry.function << std::endl;
        
        // don't show entries beneath the student's main() function, for simplicity
        if (entry.function == "main()") {
            break;
        }
    }
    if (entries.size() == 1 && entries[0].address == fakeStackPtr) {
        out << " *** (partial stack due to crash)" << std::endl;
    }

    if (STACK_TRACE_SHOW_TOP_BOTTOM_BARS && lineStrLength > 0) {
        out << " *** "
                  << std::string(lineStrLength + 2 + funcNameLength, '=') << std::endl;
    }
    
//    out << " ***" << std::endl;
//    out << " *** NOTE:" << std::endl;
//    out << " *** Any line numbers listed above are approximate." << std::endl;
//    out << " *** To learn more about why the program crashed, we" << std::endl;
//    out << " *** suggest running your program under the debugger." << std::endl;
    
    out << " ***" << std::endl;
}