Skip to content

Instantly share code, notes, and snippets.

@legnaleurc
Last active May 17, 2016 07:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save legnaleurc/1c8d4176d95c996bfd10bd6816541788 to your computer and use it in GitHub Desktop.
Save legnaleurc/1c8d4176d95c996bfd10bd6816541788 to your computer and use it in GitHub Desktop.
SpiderMonkey Stack Stalker
#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