Last active
May 17, 2016 07:45
-
-
Save legnaleurc/1c8d4176d95c996bfd10bd6816541788 to your computer and use it in GitHub Desktop.
SpiderMonkey Stack Stalker
This file contains hidden or 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
#include "mozilla/StackWalk.h" | |
#include "nsPrintfCString.h" | |
// HACK forward declartion | |
extern "C" char* PrintJSStack(); | |
void JS_smprintf_free(char*); | |
#define DEBUG_STACK_PATH "/tmp/raw_stacks.txt" | |
namespace debug { | |
/** | |
* @brief stack logger, just call LogCPPAndJSStack() | |
*/ | |
class StackStalker { | |
public: | |
static void | |
LogCPPAndJSStack () { | |
StackStalker self; | |
MozStackWalk(StackStalker::WalkStackCallback, 0, 0, &self, 0, nullptr); | |
self.logJSStack(); | |
} | |
private: | |
static void | |
WalkStackCallback (uint32_t aFrameNumber, void* aPC, void* aSP, void* | |
aClosure) { | |
StackStalker& self = *(reinterpret_cast<StackStalker*>(aClosure)); | |
MozCodeAddressDetails detail; | |
bool ok = MozDescribeCodeAddress(aPC, &detail); | |
NS_WARN_IF(!ok); | |
char current_frame[1024]; | |
MozFormatCodeAddressDetails(current_frame, sizeof(current_frame), | |
aFrameNumber, aPC, &detail); | |
self.mStacks.Append(current_frame); | |
self.mStacks.Append("\n"); | |
} | |
StackStalker () { | |
mFileOutput = fopen(DEBUG_STACK_PATH, "a"); | |
} | |
~StackStalker () { | |
fclose(mFileOutput); | |
} | |
StackStalker (const StackStalker& that); | |
StackStalker& | |
operator = (const StackStalker& that); | |
void logJSStack () const { | |
char* jsStack = PrintJSStack(); | |
if (!jsStack) { | |
fprintf(mFileOutput, "no valid JavaScript stack\n\n"); | |
JS_smprintf_free(jsStack); | |
return; | |
} | |
fprintf(mFileOutput, "%s\n%s\n\n", jsStack, mStacks.get()); | |
JS_smprintf_free(jsStack); | |
} | |
FILE* mFileOutput; | |
nsCString mStacks; | |
}; | |
// HACK call these in debugger only, or you will likely crash during GC | |
static bool | |
WriteJSONToString (const char16_t* aBuffer, uint32_t aLength, void* aData) { | |
nsAString* dst = reinterpret_cast<nsAString*>(aData); | |
dst->Append(aBuffer, aLength); | |
return true; | |
} | |
void | |
dump(JSContext* aCx, JS::HandleValue aValue) { | |
nsString json; | |
JS::RootedValue tmp(aCx, aValue); | |
JS::RootedValue indention(aCx, JS::NumberValue(2)); | |
bool ok = JS_Stringify(aCx, &tmp, nullptr, indention, WriteJSONToString, | |
&json); | |
if (ok) { | |
printf("%s\n", NS_ConvertUTF16toUTF8(json).get()); | |
} else { | |
printf("error\n"); | |
} | |
} | |
void | |
dump(JSContext* aCx, JS::HandleString* aString) { | |
JS::RootedValue tmp(aCx, JS::StringValue(*aString)); | |
dump(aCx, tmp); | |
} | |
void | |
dump(JSContext* aCx, JS::RootedValue* aValue) { | |
dump(aCx, *aValue); | |
} | |
void | |
dump(JSContext* aCx, JS::RootedObject* aObject) { | |
JS::RootedValue tmp(aCx, JS::ObjectValue(*(*aObject))); | |
dump(aCx, tmp); | |
} | |
void | |
dump(JSContext* aCx, JS::RootedString* aString) { | |
JS::RootedValue tmp(aCx, JS::StringValue(*aString)); | |
dump(aCx, tmp); | |
} | |
void | |
dump(JSContext* aCx, JS::PersistentRootedObject* aObject) { | |
JS::RootedValue tmp(aCx, JS::ObjectValue(*(*aObject))); | |
dump(aCx, tmp); | |
} | |
void | |
decompile(JSContext* aCx, JSScript* aScript) { | |
JS::RootedScript tmp(aCx, aScript); | |
JS::RootedString code(aCx, JS_DecompileScript(aCx, tmp, "shadow.js", 2U)); | |
dump(aCx, &code); | |
} | |
void | |
stack(JSContext* aCx) { | |
JS::RootedObject tmp(aCx); | |
JSAutoCompartment ac(aCx, tmp); | |
bool ok = CaptureCurrentStack(aCx, &tmp, 0); | |
NS_WARN_IF(!ok); | |
dump(aCx, &tmp); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment