-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #272 from HassoPlattnerInstituteHCI/serial/gdb
automatically convert backtrace into readable function stacktrace when detecting crash
- Loading branch information
Showing
8 changed files
with
262 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <vector> | ||
|
||
#define SAFEMOD(a, b) ((a) % (b) + (b)) % (b) | ||
|
||
class CrashAnalyzer | ||
{ | ||
private: | ||
static const uint16_t c_bufferLength = 1024; | ||
static const uint16_t c_dumpLineWidth = 32; | ||
static uint8_t s_buffer[c_bufferLength]; | ||
static uint16_t s_length; | ||
static uint16_t s_index; | ||
|
||
static void clearBuffer(); | ||
static uint8_t getChar(uint16_t offset); | ||
|
||
static const std::string c_rebootString; | ||
static const std::string c_backtraceString; | ||
|
||
static bool findString( | ||
uint16_t startOffset, | ||
uint16_t endOffset, | ||
const std::string string, | ||
uint16_t& foundOffset); | ||
static std::vector<std::string> getBacktraceAddresses( | ||
uint16_t startOffset, uint16_t endOffset); | ||
static void addr2line(std::vector<std::string> addresses); | ||
|
||
static void checkOutput(); | ||
public: | ||
static void push_back(const uint8_t character); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
#include "crashAnalyzer.hpp" | ||
|
||
#include <array> | ||
#include <cstdlib> | ||
#include <iostream> | ||
#include <fstream> | ||
#include <regex> | ||
#include <sstream> | ||
|
||
const std::string CrashAnalyzer::c_rebootString = "Rebooting..."; | ||
const std::string CrashAnalyzer::c_backtraceString = "Backtrace:"; | ||
|
||
bool CrashAnalyzer::findString( | ||
uint16_t startOffset, | ||
uint16_t endOffset, | ||
const std::string string, | ||
uint16_t& foundOffset) | ||
{ | ||
const auto length = string.length(); | ||
int32_t index = length - 1; | ||
auto offset = startOffset; | ||
|
||
while (index > -1 && offset <= endOffset) | ||
{ | ||
if(getChar(offset) == string.at(index)) | ||
{ | ||
index--; | ||
} | ||
else | ||
{ | ||
index = length - 1; | ||
} | ||
offset++; | ||
} | ||
|
||
if(index == -1) | ||
{ | ||
foundOffset = offset; | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
std::vector<std::string> CrashAnalyzer::getBacktraceAddresses( | ||
uint16_t startOffset, uint16_t endOffset) | ||
{ | ||
std::string data(startOffset - endOffset + 1, 'a'); | ||
for(auto i = startOffset; i >= endOffset; --i) | ||
{ | ||
data.at(startOffset - i) = getChar(i); | ||
} | ||
std::regex regex("(0x.{8}):0x.{8}"); | ||
auto it = std::sregex_iterator(data.begin(), data.end(), regex); | ||
auto end = std::sregex_iterator(); | ||
|
||
std::vector<std::string> result; | ||
while(it != end) | ||
{ | ||
result.push_back((*it++).str(1)); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
std::string exec(const char* cmd) { | ||
#ifdef WINDOWS | ||
#define popen _popen | ||
#define pclose _pclose | ||
#endif | ||
|
||
std::array<char, 128> buffer; | ||
std::string result; | ||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose); | ||
if (!pipe) { | ||
return "popen() failed!"; | ||
} | ||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { | ||
result += buffer.data(); | ||
} | ||
return result; | ||
} | ||
|
||
void CrashAnalyzer::addr2line(std::vector<std::string> addresses) | ||
{ | ||
std::cout << std::endl << "===== STACKTRACE BEGIN =====" << std::endl; | ||
|
||
#ifdef ADDR2LINE_PATH | ||
|
||
std::ostringstream command; | ||
command | ||
<< ADDR2LINE_PATH | ||
<< " -e ./firmware/.pio/build/esp32dev/firmware.elf" | ||
<< " -fpCis"; // see https://linux.die.net/man/1/addr2line | ||
for (const auto &address : addresses) | ||
{ | ||
command << " " << address; | ||
} | ||
|
||
const auto result = exec(command.str().c_str()); | ||
|
||
std::cout | ||
<< "Stacktrace (most recent call first):" << std::endl | ||
<< result; | ||
|
||
#else | ||
|
||
std::cout | ||
<< "Path to addr2line executable not set. Can't analyze stacktrace." | ||
<< std::endl; | ||
|
||
#endif | ||
|
||
std::cout << "====== STACKTRACE END ======" << std::endl; | ||
} | ||
|
||
void CrashAnalyzer::checkOutput() | ||
{ | ||
uint16_t rebootOffset; | ||
if(!findString( | ||
0, | ||
c_rebootString.length(), | ||
c_rebootString, | ||
rebootOffset)) | ||
{ | ||
return; | ||
} | ||
|
||
uint16_t backtraceOffset; | ||
if(!findString( | ||
rebootOffset, | ||
s_length, | ||
c_backtraceString, | ||
backtraceOffset)) | ||
{ | ||
std::cout << "Reboot detected, but no backtrace found." << std::endl; | ||
return; | ||
} | ||
|
||
auto addresses = getBacktraceAddresses( | ||
backtraceOffset - c_backtraceString.length() - 1, | ||
rebootOffset); | ||
|
||
addr2line(addresses); | ||
clearBuffer(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#include "crashAnalyzer.hpp" | ||
|
||
#include <iomanip> | ||
#include <iostream> | ||
|
||
uint8_t CrashAnalyzer::s_buffer[c_bufferLength]; | ||
uint16_t CrashAnalyzer::s_length = 0; | ||
uint16_t CrashAnalyzer::s_index = 0; | ||
|
||
void CrashAnalyzer::clearBuffer() | ||
{ | ||
s_index = 0; | ||
s_length = 0; | ||
} | ||
|
||
uint8_t CrashAnalyzer::getChar(uint16_t offset) | ||
{ | ||
return s_buffer[SAFEMOD((s_index - offset), c_bufferLength)]; | ||
} | ||
|
||
void CrashAnalyzer::push_back(const uint8_t character) | ||
{ | ||
s_buffer[s_index] = character; | ||
s_index = (s_index + 1) % c_bufferLength; | ||
s_length = (s_length >= c_bufferLength) ? c_bufferLength : (s_length + 1); | ||
|
||
checkOutput(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters