/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ // DataOutput.cpp // // Scott M. Silver #include #include #include #include #include "Debugee.h" #include "XDisAsm.h" #include "Win32Util.h" #include "DataOutput.h" #include "DebuggerChannel.h" #include "Breakpoints.h" void* disassembleToString(DebugeeProcess& inProcess, void* inStart, const char* inOutputBuffer); void* printOneInstruction(DebugeeProcess& inProcess, void* inStart); extern bool gCommandLineLoopActive; extern "C" rl_clear_screen(); extern DebugeeThread* gCurThread; void disassembleBytes(DebugeeProcess& inProcess, const char* inStart, int /*length*/) { printOneInstruction(inProcess, (void*) inStart); putchar('\n'); } void* disassembleToString(DebugeeProcess& inProcess, void* inStart, char* outOutputBuffer) { unsigned char data[32]; if (!inProcess.readMemory(inStart, &data, 32, NULL)) showLastError(); // if the current pc is the site of breakpoint // we replace the breakpoint instruction with // the replaced instruction Breakpoint* bp = BreakpointManager::findBreakpoint(inStart); if (bp) data[0] = bp->getReplaced(); unsigned char* tempStart = data; if (data[0] == 0xe8 || data[0] == 0xe9) { // call/jmp with 32 bit offset relative to pc from end of the instruction char symbol[512]; DWORD offset; void* address = (void*) ((Uint8*) inStart + *((Int32*) (data + 1)) + 5); // 5 is length of instruction if (inProcess.getSymbol(address, symbol, sizeof(symbol), offset)) { sprintf(outOutputBuffer, "%s\t %s + %d; %p", (data[0] == 0xe8) ? "call" : "jmp", symbol, offset, address); goto FinishDisassembling; } // else false through and do the normal thing } // regular instruction char* str; str = disasmx86(0, (char**) &tempStart, (char*)data + 32, kDisAsmFlag32BitSegments); strcpy(outOutputBuffer, str); FinishDisassembling: tempStart = data; return ((void*) ((char*) inStart + x86InstructionLength(0, (char**)&tempStart, (char*) data + 32, kDisAsmFlag32BitSegments))); } DebugeeProcess::SymbolKind printMethodName(DebugeeProcess& inProcess, const void* inMethodAddress) { char symbol[512]; DWORD offset; DebugeeProcess::SymbolKind kind; if ((kind = inProcess.getSymbol(inMethodAddress, symbol, sizeof(symbol), offset)) != DebugeeProcess::kNil) printf("%s + %d", symbol, offset); return (kind); } void* printOneInstruction(DebugeeProcess& inProcess, void* inStart) { void* nextPC; char buffer[1024]; nextPC = disassembleToString(inProcess, inStart, buffer); printf("%.8x: %s", inStart, buffer); return (nextPC); } void* disassembleN(DebugeeProcess& inProcess, const char* inStart, int inInstructions) { int curInstruction; void* curPC = (void*) inStart; if (printMethodName(inProcess, inStart)); putchar('\n'); for (curInstruction = 0; curInstruction < inInstructions; curInstruction++) { curPC = printOneInstruction(inProcess, curPC); printf("\n"); } return (curPC); } void beginOutput() { if (gCommandLineLoopActive) putchar('\n'); } void endOutput() { if (gCommandLineLoopActive) rl_clear_screen(); } void printThreads(DebugeeProcess& inProcess) { Vector threads = inProcess.getThreads(); printf(" %4s%5s%10s(%5s)%9s %s\n", "id", "hndl", "state", "cnt", "eip", "symbol"); DebugeeThread** curThread; for(curThread = threads.begin(); curThread < threads.end(); curThread++) { if (gCurThread == *curThread) printf("*"); else printf(" "); (*curThread)->print(); printf("\n"); } } void printThreadStack(DebugeeThread& inThread) { STACKFRAME stackFrame; CONTEXT context; ::ZeroMemory(&stackFrame, sizeof(stackFrame)); inThread.getContext(CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS, context); stackFrame.AddrPC.Offset = context.Eip; stackFrame.AddrPC.Mode = AddrModeFlat; stackFrame.AddrStack.Offset = context.Esp; stackFrame.AddrStack.Mode = AddrModeFlat; stackFrame.AddrFrame.Offset = context.Ebp; stackFrame.AddrFrame.Mode = AddrModeFlat; DebugeeProcess::SymbolKind state; for (;;) { if (stackFrame.AddrPC.Offset == 0) break; state = printMethodName(inThread.getProcess(), (void*) stackFrame.AddrPC.Offset); if (state == DebugeeProcess::kJava) { printf("\n"); inThread.getProcess().readMemory(((DWORD*)stackFrame.AddrFrame.Offset + 1), &stackFrame.AddrPC.Offset, 4); inThread.getProcess().readMemory((void*) stackFrame.AddrFrame.Offset, &stackFrame.AddrFrame.Offset, 4); stackFrame.AddrStack.Offset = stackFrame.AddrFrame.Offset; } else if (state == DebugeeProcess::kNative) { printf("\n"); if (!::StackWalk(IMAGE_FILE_MACHINE_I386, inThread.getProcess().getProcessHandle(), inThread.getThreadHandle(), &stackFrame, NULL, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL)) { inThread.getProcess().readMemory(((DWORD*)stackFrame.AddrFrame.Offset + 1), &stackFrame.AddrPC.Offset, 4); inThread.getProcess().readMemory((void*) stackFrame.AddrFrame.Offset, &stackFrame.AddrFrame.Offset, 4); stackFrame.AddrStack.Offset = stackFrame.AddrFrame.Offset; } } else { // try one more native frame if (::StackWalk(IMAGE_FILE_MACHINE_I386, inThread.getProcess().getProcessHandle(), inThread.getThreadHandle(), &stackFrame, NULL, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL)) state = printMethodName(inThread.getProcess(), (void*) stackFrame.AddrPC.Offset); else { printf("\n"); break; } } } // showLastError(); } void printIntegerRegs(DebugeeThread& inThread) { CONTEXT context; gCurThread->getContext(CONTEXT_INTEGER | CONTEXT_CONTROL, context); printf( "EDI=%8p ESI=%8p EBX=%8p EDX=%8p\n" "ECX=%8p EAX=%8p EBP=%8p ESP=%8p\n" "EIP=%8p\n", context.Edi, context.Esi, context.Ebx, context.Edx, context.Ecx, context.Eax, context.Ebp, context.Esp, context.Eip); } void printFlags(DebugeeThread& inThread) { CONTEXT context; gCurThread->getContext(CONTEXT_CONTROL, context); const char* flagString = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; const char* cp = flagString; while (context.EFlags) { if (context.EFlags & 1) putchar(*cp); else putchar(*cp - 32); cp++; context.EFlags >>= 1; } }