static void emergencyDump(int quit) { extern sqInt preSnapshot(void); extern sqInt postSnapshot(void); extern void writeImageFile(sqInt); char savedName[MAXPATHLEN]; char baseName[MAXPATHLEN]; char *term; int dataSize, i; strncpy(savedName, imageName, MAXPATHLEN); strncpy(baseName, imageName, MAXPATHLEN); if ((term= strrchr(baseName, '.'))) *term= '\0'; for (i= 0; ++i;) { struct stat sb; sprintf(imageName, "%s-emergency-dump-%d.image", baseName, i); if (stat(imageName, &sb)) break; } dataSize= preSnapshot(); writeImageFile(dataSize); fprintf(stderr, "\n"); printCallStack(); fprintf(stderr, "\nTo recover valuable content from this image:\n"); fprintf(stderr, " squeak %s\n", imageName); fprintf(stderr, "and then evaluate\n"); fprintf(stderr, " Smalltalk processStartUpList: true\n"); fprintf(stderr, "in a workspace. DESTROY the dumped image after recovering content!"); if (quit) abort(); strncpy(imageName, savedName, sizeof(imageName)); }
static void sigsegv(int ignore) { /* error("Segmentation fault"); */ static int printingStack= 0; printf("\nSegmentation fault\n\n"); if (!printingStack) { printingStack= 1; printCallStack(); } abort(); }
// // debugging convenience // void printCallStack() { printCallStack(true, true, stdout); }
static void printCallStackOnError() { printCallStack(false, false, stderr); }
void HandlePrefsMenu(int cmd) { switch(cmd) { case ID_ABOUT: MessageBox(stWindow,VM_VERSION_TEXT, TEXT("About ") TEXT(VM_NAME) TEXT(" on Win32"), MB_OK); break; case ID_DEFERUPDATES: fDeferredUpdate = !fDeferredUpdate; SetDeferredUpdate(); break; case ID_SHOWCONSOLE: fShowConsole = !fShowConsole; SetShowConsole(); break; case ID_DYNAMICCONSOLE: fDynamicConsole = !fDynamicConsole; SetDynamicConsole(); break; case ID_REDUCECPUUSAGE: fReduceCPUUsage = !fReduceCPUUsage; SetReduceCPUUsage(); break; case ID_3BUTTONMOUSE: f3ButtonMouse = !f3ButtonMouse; Set3ButtonMouse(); break; case ID_DEFAULTPRINTER: SetTheDefaultPrinter(); break; case ID_REDUCEBACKGROUNDCPU: fReduceCPUInBackground = !fReduceCPUInBackground; SetReduceCPUInBackground(); break; case ID_1BUTTONMOUSE: f1ButtonMouse = !f1ButtonMouse; Set1ButtonMouse(); break; case ID_DIRECTSOUND: fUseDirectSound = !fUseDirectSound; SetUseDirectSound(); break; case ID_FILEACCESS: _ioSetFileAccess(!ioHasFileAccess()); SetAllowFileAccess(); break; case ID_IMAGEWRITE: _ioSetImageWrite(!ioCanWriteImage()); SetAllowImageWrite(); break; case ID_SHOWALLOCATIONS: fShowAllocations = !fShowAllocations; SetShowAllocations(); break; #ifndef NO_NETWORK case ID_SOCKETACCESS: _ioSetSocketAccess(!ioHasSocketAccess()); SetAllowSocketAccess(); break; case ID_DBGPRINTSOCKET: win32DebugPrintSocketState(); break; #endif case ID_DBGPRINTSTACK: printCallStack(); break; case ID_PRINTALLSTACKS: printf("Printing all processes:\n"); printAllStacks(); break; #if STACKVM case ID_DUMPPRIMLOG: { extern void dumpPrimTraceLog(void); printf("Printing recent primitives:\n"); dumpPrimTraceLog(); break; } #endif case ID_PRIORITYBOOST: fPriorityBoost = !fPriorityBoost; SetPriorityBoost(); break; case ID_USEOPENGL: fUseOpenGL = !fUseOpenGL; SetB3DXUsesOpenGL(); break; case ID_CASEFILES: printf("case files %d\n", caseSensitiveFileMode); caseSensitiveFileMode = !caseSensitiveFileMode; SetCaseSensitiveFileMode(); printf("case files %d\n", caseSensitiveFileMode); break; } }
ProcStatus ProcDecompiler::tryDecompileRecursive(UserProc *proc) { /* Cycle detection logic: * ********************* * cycleGrp is an initially null pointer to a set of procedures, representing the procedures * involved in the current recursion group, if any. These procedures have to be analysed * together as a group, after individual pre-group analysis. child is a set of procedures, * cleared at the top of decompile(), representing the cycles associated with the current * procedure and all of its children. If this is empty, the current procedure is not involved in * recursion, and can be decompiled up to and including removing unused statements. callStack is * an initially empty list of procedures, representing the call stack from the current entry * point to the current procedure, inclusive. If (after all children have been processed: * important!) the first element in callStack and also cycleGrp is the current procedure, we * have the maximal set of distinct cycles, so we can do the recursion group analysis and return * an empty set. At the end of the recursion group analysis, the whole group is complete, ready * for the global analyses. * * cycleSet decompile(ProcList callStack) // call stack initially empty * child = new ProcSet * push this proc to the call stack * for each child c called by this proc * if c has already been visited but not finished * // have new cycle * if c is in callStack * // this is a completely new cycle * insert every proc from c to the end of callStack into child * else * // this is a new branch of an existing cycle * child = c->cycleGrp * find first element f of callStack that is in cycleGrp * insert every proc after f to the end of callStack into child * for each element e of child * insert e->cycleGrp into child * e->cycleGrp = child * else * // no new cycle * tmp = c->decompile(callStack) * child = union(child, tmp) * set return statement in call to that of c * * if (child empty) * earlyDecompile() * child = middleDecompile() * removeUnusedStatments() // Not involved in recursion * else * // Is involved in recursion * find first element f in callStack that is also in cycleGrp * if (f == this) // The big test: have we got the complete strongly connected component? * recursionGroupAnalysis() // Yes, we have * child = new ProcSet // Don't add these processed cycles to the parent * remove last element (= this) from callStack * return child */ Project *project = proc->getProg()->getProject(); LOG_MSG("%1 procedure '%2'", (proc->getStatus() >= PROC_VISITED) ? "Re-visiting" : "Visiting", proc->getName()); project->alertDiscovered(proc); // Prevent infinite loops when there are cycles in the call graph (should never happen now) if (proc->getStatus() >= PROC_FINAL) { LOG_WARN("Proc %1 already has status PROC_FINAL", proc->getName()); return PROC_FINAL; // Already decompiled } if (proc->getStatus() < PROC_DECODED) { // Can happen e.g. if a callee is visible only after analysing a switch statement // Actually decoding for the first time, not REdecoding if (!proc->getProg()->reDecode(proc)) { return PROC_UNDECODED; } } if (proc->getStatus() < PROC_VISITED) { proc->setStatus(PROC_VISITED); // We have at least visited this proc "on the way down" } m_callStack.push_back(proc); if (project->getSettings()->verboseOutput) { printCallStack(); } if (project->getSettings()->decodeChildren) { // Recurse to callees first, to perform a depth first search for (BasicBlock *bb : *proc->getCFG()) { if (bb->getType() != BBType::Call) { continue; } // The call Statement will be in the last RTL in this BB CallStatement *call = static_cast<CallStatement *>(bb->getRTLs()->back()->getHlStmt()); if (!call->isCall()) { LOG_WARN("BB at address %1 is a CALL but last stmt is not a call: %2", bb->getLowAddr(), call); continue; } assert(call->isCall()); UserProc *callee = dynamic_cast<UserProc *>(call->getDestProc()); if (callee == nullptr) { // not an user proc, or missing dest continue; } if (callee->getStatus() == PROC_FINAL) { // Already decompiled, but the return statement still needs to be set for this call call->setCalleeReturn(callee->getRetStmt()); continue; } // check if the callee has already been visited but not done (apart from global // analyses). This means that we have found a new cycle or a part of an existing cycle if ((callee->getStatus() >= PROC_VISITED) && (callee->getStatus() <= PROC_EARLYDONE)) { // if callee is in callStack ProcList::iterator calleeIt = std::find(m_callStack.begin(), m_callStack.end(), callee); if (calleeIt != m_callStack.end()) { // This is a completely new cycle std::shared_ptr<ProcSet> newRecursionGroup(new ProcSet()); newRecursionGroup->insert(calleeIt, m_callStack.end()); createRecursionGoup(newRecursionGroup); } else if (callee->getRecursionGroup()) { // This is a new branch of an existing cycle that was visited previously std::shared_ptr<ProcSet> recursionGroup = callee->getRecursionGroup(); // Find first element func of callStack that is in callee->recursionGroup ProcList::iterator _pi = std::find_if( m_callStack.begin(), m_callStack.end(), [callee](UserProc *func) { return callee->getRecursionGroup()->find(func) != callee->getRecursionGroup()->end(); }); // Insert every proc after func to the end of path into child assert(_pi != m_callStack.end()); for (auto it = std::next(_pi); it != m_callStack.end(); ++it) { addToRecursionGroup(*it, recursionGroup); } } proc->setStatus(PROC_INCYCLE); } else { // No new cycle LOG_VERBOSE("Preparing to decompile callee '%1' of '%2'", callee->getName(), proc->getName()); callee->promoteSignature(); tryDecompileRecursive(callee); // Child has at least done middleDecompile(), possibly more call->setCalleeReturn(callee->getRetStmt()); if (proc->getStatus() != PROC_INCYCLE && m_recursionGroups.find(proc) != m_recursionGroups.end()) { proc->setStatus(PROC_INCYCLE); proc->setRecursionGroup(m_recursionGroups.find(proc)->second); } } } } // if no child involved in recursion if (proc->getStatus() != PROC_INCYCLE) { project->alertDecompiling(proc); LOG_MSG("Decompiling procedure '%1'", proc->getName()); earlyDecompile(proc); middleDecompile(proc); if (project->getSettings()->verboseOutput) { printCallStack(); } } if (proc->getStatus() != PROC_INCYCLE) { lateDecompile(proc); // Do the whole works proc->setStatus(PROC_FINAL); project->alertEndDecompile(proc); } else if (m_recursionGroups.find(proc) != m_recursionGroups.end()) { // This proc's callees, and hence this proc, is/are involved in recursion. // Find first element f in path that is also in our recursion group ProcList::iterator f = std::find_if( m_callStack.begin(), m_callStack.end(), [proc](UserProc *func) { return proc->getRecursionGroup()->find(func) != proc->getRecursionGroup()->end(); }); // The big test: have we found the whole strongly connected component (in the call graph)? if (*f == proc) { // Yes, process these procs as a group recursionGroupAnalysis(proc->getRecursionGroup()); proc->setStatus(PROC_FINAL); project->alertEndDecompile(proc); } } // Remove last element (= this) from path assert(!m_callStack.empty()); assert(m_callStack.back() == proc); m_callStack.pop_back(); LOG_MSG("Finished decompile of '%1'", proc->getName()); if (project->getSettings()->verboseOutput) { printCallStack(); } return proc->getStatus(); }