зеркало из https://github.com/mozilla/gecko-dev.git
288 строки
7.0 KiB
C++
288 строки
7.0 KiB
C++
/* -*- 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 <assert.h>
|
|
#include <stdio.h>
|
|
#include <Windows.h>
|
|
#include <ImageHlp.h>
|
|
#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<DebugeeThread*> 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("<anonymous>\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;
|
|
}
|
|
}
|
|
|