ultimatepp/uppsrc/ide/Debuggers/Code.cpp
cxl e39062e81d ide: 64-bit pdb debugging
git-svn-id: svn://ultimatepp.org/upp/trunk@7581 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2014-08-10 17:33:31 +00:00

340 lines
5.9 KiB
C++

#include "Debuggers.h"
#ifdef COMPILER_MSC
#define LLOG(x) // DLOG(x)
int Pdb::Disassemble(adr_t ip)
{
char out[256];
byte code[32];
memset(code, 0, 32);
int i;
for(i = 0; i < 32; i++) {
int q = Byte(i + ip);
if(q < 0)
break;
code[i] = q;
}
#ifdef CPU_64
int sz = NDisassemble(out, code, ip, win64);
#else
int sz = NDisassemble(out, code, ip);
#endif
if(sz > i)
return -1;
disas.Add(ip, out, Null, String(code, sz));
CParser p(out);
while(!p.IsEof()) {
try {
if(p.Char2('0', 'x'))
disas.AddT((adr_t)p.ReadNumber64(16));
}
catch(CParser::Error) {}
p.SkipTerm();
}
return sz;
}
bool Pdb::IsValidFrame(adr_t eip)
{
for(int i = 0; i < module.GetCount(); i++) {
const ModuleInfo& f = module[i];
if(eip >= f.base && eip < f.base + f.size)
return true;
}
return false;
}
adr_t Pdb::GetIP()
{
#ifdef CPU_64
if(win64)
return context.context64.Rip;
#endif
return context.context32.Eip;
}
void Pdb::Sync()
{
threadlist.Clear();
for(int i = 0; i < threads.GetCount(); i++) {
int thid = threads.GetKey(i);
AttrText x(Format("0x%x", thid));
if(thid == event.dwThreadId)
x.font = StdFont().Bold();
threadlist.Add(thid, x);
}
threadlist <<= (int)event.dwThreadId;
Sync0();
SetFrame();
IdeActivateBottom();
}
void Pdb::SetThread()
{
Sync0();
SetFrame();
IdeActivateBottom();
}
void Pdb::SetFrame()
{
int fi = ~framelist;
if(fi >= 0 && fi < frame.GetCount()) {
Frame& f = frame[fi];
bool df = disas.HasFocus();
FilePos fp = GetFilePos(f.pc);
IdeHidePtr();
autotext.Clear();
Image ptrimg = fi == 0 ? DbgImg::IpLinePtr() : DbgImg::FrameLinePtr();
if(fp) {
IdeSetDebugPos(fp.path, fp.line, ptrimg, 0);
autotext.Clear();
for(int i = -4; i < 4; i++)
autotext << ' ' << IdeGetLine(fp.line + i);
}
if(!disas.InRange(f.pc) || f.fn.name != disas_name) {
disas_name = f.fn.name;
disas.Clear();
adr_t ip = f.fn.address;
adr_t h = f.fn.address + f.fn.size;
if(f.pc < ip || f.pc >= h) {
ip = f.pc - 64;
h = ip + 1024;
}
while(ip < h) {
int sz = Disassemble(ip);
if(sz < 0)
break;
ip += sz;
}
}
disas.SetCursor(f.pc);
disas.SetIp(f.pc, ptrimg);
if(df)
disas.SetFocus();
Data();
}
}
bool Pdb::SetBreakpoint(const String& filename, int line, const String& bp)
{
adr_t a = GetAddress(FilePos(filename, line));
if(!a)
return false;
int q = breakpoint.Find(a);
if(bp.IsEmpty()) {
if(q >= 0) {
if(!RemoveBp(a))
return false;
breakpoint.Remove(q);
}
}
else {
if(q < 0) {
if(!AddBp(a))
return false;
breakpoint.Add(a);
}
}
return true;
}
adr_t Pdb::CursorAdr()
{
adr_t a = disas.HasFocus() ? disas.GetCursor() : GetAddress(FilePos(IdeGetFileName(), IdeGetFileLine()));
if(!a)
Exclamation("No code at choosen location !");
return a;
}
bool Pdb::RunTo()
{
LLOG("== RunTo");
adr_t a = CursorAdr();
if(!a)
return false;
if(!SingleStep())
return false;
if(GetIP() != a) {
SetBreakpoints();
AddBp(a);
if(!Continue())
return false;
}
Sync();
return true;
}
void Pdb::Run()
{
LLOG("== Run");
SingleStep();
SetBreakpoints();
if(!Continue()) {
LLOG("Run: !Continue");
return;
}
LLOG("Run: Sync");
Sync();
}
void Pdb::SetIp()
{
adr_t a = CursorAdr();
if(!a)
return;
#ifdef CPU_64
if(win64)
context.context64.Rip = a;
else
#endif
context.context32.Eip = (DWORD)a;
WriteContext();
frame[0].pc = a;
framelist <<= 0;
SetFrame();
}
bool Pdb::Step(bool over)
{
LLOG("== Step over: " << over);
TimeStop ts;
adr_t ip = GetIP();
byte b = Byte(ip);
byte b1 = (Byte(ip + 1) >> 3) & 7;
if(b == 0xe8 || b == 0x9a || b == 0xff && (b1 == 2 || b1 == 3)) { // Various CALL forms
LLOG("Stepping over CALL");
if(over) {
int l = 5;
if(b != 0xe8) {
char out[256];
byte code[32];
memset(code, 0, 32);
adr_t ip = GetIP();
for(int i = 0; i < 32; i++) {
int q = Byte(ip + i);
if(q < 0)
break;
code[i] = q;
}
#ifdef CPU_64
l = NDisassemble(out, code, GetIP(), win64);
#else
l = NDisassemble(out, code, GetIP());
#endif
}
adr_t bp0 = GetIP();
adr_t bp = bp0 + l;
int lvl = 0;
Lock();
for(;;) {
if(!SingleStep()) { // Step into function
Unlock();
return false;
}
SetBreakpoints(); // Note: Do we really want to do this? (activates breakpoints)
if(breakpoint.Find(bp0) < 0)
AddBp(bp0);
else
bp0 = 0;
AddBp(bp);
if(!Continue()) {
Unlock();
return false;
}
if(GetIP() == bp0)
lvl++; // Recursive call
else
if(GetIP() == bp) {
if(lvl <= 0) {
Unlock(); // Base level - stepping ended
return true;
}
lvl--;
}
else {
Unlock(); // Any other breakpoint
return true;
}
if(ts.Elapsed() > 100)
Ctrl::ProcessEvents();
}
}
else {
if(!SingleStep())
return false;
byte b = Byte(GetIP());
if(b == 0xeb || b == 0xe9) // Step over JMP following CALL (windows jump tables)
return SingleStep();
return true;
}
}
else
return SingleStep();
}
void Pdb::Trace(bool over)
{
LLOG("== Trace over: " << over);
adr_t ip0 = GetIP();
FilePos p0 = GetFilePos(ip0);
if(IsNull(p0.path) || disas.HasFocus()) {
if(!Step(over))
return;
Sync();
return;
}
bool locked = false;
int n = 0;
TimeStop ts;
for(;;) {
if(ts.Elapsed() > 100) {
if(!locked) {
Lock();
locked = true;
}
ProcessEvents();
}
if(!Step(over))
break;
adr_t ip = GetIP();
FilePos p = GetFilePos(ip);
if(ip < ip0 || p.path != p0.path || p.line != p0.line || stop) {
Sync();
break;
}
}
if(locked)
Unlock();
}
void Pdb::StepOut()
{
LLOG("== StepOut");
Lock();
TimeStop ts;
for(;;) {
adr_t ip = GetIP();
if(Byte(ip) == 0xc2 || Byte(ip) == 0xc3) {
if(!SingleStep())
break;
Sync();
break;
}
if(stop) {
Sync();
break;
}
if(!Step(true))
break;
if(ts.Elapsed() > 100)
Ctrl::ProcessEvents();
}
Unlock();
}
#endif