2019-08-23 11:56:54 -07:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Text;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using Beefy;
|
|
|
|
using Beefy.gfx;
|
|
|
|
using Beefy.widgets;
|
|
|
|
using Beefy.theme.dark;
|
|
|
|
using Beefy.utils;
|
|
|
|
using Beefy.geom;
|
|
|
|
using IDE.Compiler;
|
|
|
|
using IDE.Debugger;
|
|
|
|
using System.IO;
|
|
|
|
using IDE.util;
|
|
|
|
|
|
|
|
namespace IDE.ui
|
|
|
|
{
|
|
|
|
public class DisassemblyEditContent : SourceEditWidgetContent
|
|
|
|
{
|
|
|
|
public DisassemblyPanel mDisassemblyPanel;
|
|
|
|
|
|
|
|
public float mJmpIconY;
|
|
|
|
public int mJmpState = -1;
|
|
|
|
|
|
|
|
public override void MouseClicked(float x, float y, int32 btn)
|
|
|
|
{
|
|
|
|
base.MouseClicked(x, y, btn);
|
|
|
|
|
|
|
|
if (btn == 1)
|
|
|
|
{
|
|
|
|
//var sourceViewPanel = (SourceViewPanel)mParent.mParent;
|
|
|
|
|
|
|
|
Menu menu = new Menu();
|
|
|
|
if (!String.IsNullOrEmpty(mDisassemblyPanel.mSourceFileName))
|
|
|
|
{
|
|
|
|
var menuItem = menu.AddItem("Go to Source");
|
|
|
|
menuItem.mOnMenuItemSelected.Add(new (evt) => mDisassemblyPanel.GoToSource());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*menu.AddItem("Item 2");
|
|
|
|
menu.AddItem();
|
|
|
|
menu.AddItem("Item 3");*/
|
|
|
|
|
|
|
|
MenuWidget menuWidget = DarkTheme.sDarkTheme.CreateMenuWidget(menu);
|
|
|
|
|
|
|
|
if (menu.mItems.Count > 0)
|
|
|
|
menuWidget.Init(this, x, y);
|
|
|
|
else
|
|
|
|
delete menuWidget;
|
|
|
|
//menuWidget.mWidgetWindow.mWindowClosedHandler += MenuClosed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*if (btn == 0)
|
|
|
|
{
|
|
|
|
let fileName = scope String();
|
|
|
|
int addr = mDisassemblyPanel.GetCursorAddress(fileName);
|
|
|
|
Debug.WriteLine("{0} : {1:X}", fileName, addr);
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void Draw(Graphics g)
|
|
|
|
{
|
|
|
|
base.Draw(g);
|
|
|
|
|
|
|
|
float lineSpacing = mFont.GetLineSpacing();
|
|
|
|
int32 cursorLine = CursorLineAndColumn.mLine;
|
|
|
|
|
|
|
|
for (int32 pass = 0; pass < 2; pass++)
|
|
|
|
{
|
|
|
|
for (var jumpEntry in mDisassemblyPanel.mJumpTable)
|
|
|
|
{
|
|
|
|
var minLineResult = mDisassemblyPanel.mAddrLines.GetValue(jumpEntry.mAddrMin);
|
|
|
|
var maxLineResult = mDisassemblyPanel.mAddrLines.GetValue(jumpEntry.mAddrMax);
|
|
|
|
|
|
|
|
if ((minLineResult case .Ok) && (maxLineResult case .Ok))
|
|
|
|
{
|
|
|
|
int32 minLine = minLineResult;
|
|
|
|
int32 maxLine = maxLineResult;
|
|
|
|
|
|
|
|
bool isHilighted = (cursorLine == minLine) || (cursorLine == maxLine);
|
|
|
|
|
|
|
|
if (isHilighted != (pass == 1))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
uint32 color = jumpEntry.mIsReverse ?
|
|
|
|
(isHilighted ? 0xFFffeafe : 0xFF8a7489) :
|
|
|
|
(isHilighted ? 0xFFeaf5ff : 0xFF72828f);
|
|
|
|
|
|
|
|
float minY = 0 + minLine * lineSpacing + 6;
|
|
|
|
float maxY = 0 + maxLine * lineSpacing + 6;
|
|
|
|
float width = 21 + jumpEntry.mDepth * 7;
|
|
|
|
|
|
|
|
using (g.PushColor(color))
|
|
|
|
{
|
|
|
|
//g.FillRect(50 - width, minY - 4, width, maxY - minY + 7);
|
|
|
|
|
|
|
|
//g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.AsmArrow), 50 - width, minY - 4, width, maxY - minY + 7);
|
|
|
|
|
|
|
|
if (!jumpEntry.mIsReverse)
|
|
|
|
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.AsmArrow), 50 - width, minY - 4, width, maxY - minY + 7);
|
|
|
|
else
|
|
|
|
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.AsmArrowRev), 50 - width, minY - 4, width, maxY - minY + 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var overlapDepth in jumpEntry.mOverlapsAtMin)
|
|
|
|
{
|
|
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.AsmArrowShadow), 26 - overlapDepth * 7, minY - 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var overlapDepth in jumpEntry.mOverlapsAtMax)
|
|
|
|
{
|
|
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.AsmArrowShadow), 26 - overlapDepth * 7, maxY - 10);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mJmpState != -1)
|
|
|
|
{
|
|
|
|
var img = (mJmpState == 0) ? DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.NoJmp) : DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.YesJmp);
|
|
|
|
g.Draw(img, 34, mJmpIconY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class DisassemblyEdit : SourceEditWidget
|
|
|
|
{
|
|
|
|
public this() : base(null, new DisassemblyEditContent())
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class DisassemblyPanel : TextPanel
|
|
|
|
{
|
|
|
|
public struct LineData
|
|
|
|
{
|
|
|
|
public int mAddr;
|
|
|
|
public int mAddrEnd;
|
|
|
|
public String mSourceFile;
|
|
|
|
public int32 mSourceLineNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
public class JumpEntry
|
|
|
|
{
|
|
|
|
public int mAddrMin;
|
|
|
|
public int mAddrMax;
|
|
|
|
public bool mIsReverse;
|
|
|
|
public int32 mDepth;
|
|
|
|
|
|
|
|
public List<int32> mOverlapsAtMin = new List<int32>() ~ delete _;
|
|
|
|
public List<int32> mOverlapsAtMax = new List<int32>() ~ delete _;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String sPanelName = "Disassembly";
|
|
|
|
|
|
|
|
public DisassemblyEdit mEditWidget;
|
|
|
|
PanelHeader mPanelHeader;
|
|
|
|
//string[] mSourceLines;
|
|
|
|
List<int32> mLineStarts ~ delete _;
|
|
|
|
EditWidgetContent.CharData[] mCharData ~ delete _;
|
|
|
|
String mDiasmSourceFileName ~ delete _;
|
|
|
|
List<LineData> mLineDatas = new List<LineData>() ~ delete _;
|
|
|
|
public List<JumpEntry> mJumpTable = new List<JumpEntry>() ~ DeleteContainerAndItems!(_);
|
|
|
|
public Dictionary<int, int32> mAddrLines = new Dictionary<int, int32>() ~ delete _;
|
|
|
|
public bool mIsInitialized;
|
|
|
|
Dictionary<int, Breakpoint> mBreakpointAddrs = new .() ~ delete _;
|
|
|
|
public bool mLocationDirty;
|
|
|
|
private int mDeferredAddr;
|
|
|
|
public DarkCheckBox mStayInDisassemblyCheckbox;
|
|
|
|
public int32 mSourceStackIdx;
|
|
|
|
int32 mSourceLine;
|
|
|
|
int32 mSourceColumn;
|
|
|
|
int32 mHotIdx;
|
|
|
|
int32 mDefLineStart;
|
|
|
|
int32 mDefLineEnd;
|
|
|
|
bool mIsRawDiassembly;
|
|
|
|
public String mSourceFileName ~ delete _;
|
|
|
|
public String mAliasFilePath ~ delete _;
|
|
|
|
public SourceHash mSourceHash;
|
|
|
|
|
|
|
|
public this()
|
|
|
|
{
|
|
|
|
mEditWidget = new DisassemblyEdit();
|
|
|
|
var content = (DisassemblyEditContent)mEditWidget.Content;
|
|
|
|
content.mDisassemblyPanel = this;
|
|
|
|
content.mIsMultiline = true;
|
|
|
|
content.mIsReadOnly = true;
|
|
|
|
content.mWordWrap = false;
|
|
|
|
content.mTextInsets.mLeft = 48;
|
|
|
|
content.SetFont(IDEApp.sApp.mCodeFont, true, true);
|
|
|
|
|
|
|
|
content.mTextColors = SourceEditWidgetContent.sTextColors;
|
|
|
|
|
|
|
|
mEditWidget.InitScrollbars(true, true);
|
|
|
|
AddWidget(mEditWidget);
|
|
|
|
|
|
|
|
Disable();
|
|
|
|
}
|
|
|
|
|
|
|
|
public ~this()
|
|
|
|
{
|
|
|
|
RemovePanelHeader();
|
|
|
|
if (mStayInDisassemblyCheckbox != null)
|
|
|
|
delete mStayInDisassemblyCheckbox;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override SourceEditWidget EditWidget
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return mEditWidget;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void Serialize(StructuredData data)
|
|
|
|
{
|
|
|
|
base.Serialize(data);
|
|
|
|
|
|
|
|
data.Add("Type", "DisassemblyPanel");
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool Deserialize(StructuredData data)
|
|
|
|
{
|
|
|
|
return base.Deserialize(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void FocusEdit()
|
|
|
|
{
|
|
|
|
mEditWidget.SetFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ClearQueuedData()
|
|
|
|
{
|
|
|
|
mDeferredAddr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetFile(String fileName, out bool isOld)
|
|
|
|
{
|
2019-11-22 12:27:13 -08:00
|
|
|
mSourceHash = .();
|
2019-08-23 11:56:54 -07:00
|
|
|
isOld = false;
|
|
|
|
String useFileName = scope String(fileName);
|
|
|
|
if (mAliasFilePath != null)
|
|
|
|
{
|
|
|
|
if (Path.Equals(useFileName, mAliasFilePath))
|
|
|
|
useFileName.Set(mSourceFileName);
|
|
|
|
}
|
|
|
|
|
|
|
|
IDEUtils.FixFilePath(useFileName);
|
|
|
|
String.NewOrSet!(mDiasmSourceFileName, useFileName);
|
|
|
|
var app = IDEApp.sApp;
|
|
|
|
delete mLineStarts;
|
|
|
|
delete mCharData;
|
|
|
|
mLineStarts = null;
|
|
|
|
mCharData = null;
|
|
|
|
|
|
|
|
String text = null;
|
|
|
|
ProjectSource projectSource = app.FindProjectSourceItem(useFileName);
|
|
|
|
if (projectSource != null)
|
|
|
|
{
|
|
|
|
IdSpan liveCharIdData;
|
|
|
|
String liveText = scope:: String();
|
|
|
|
app.FindProjectSourceContent(projectSource, out liveCharIdData, true, liveText);
|
|
|
|
defer(stack) liveCharIdData.Dispose();
|
|
|
|
|
|
|
|
var compileInstance = IDEApp.sApp.mWorkspace.GetProjectSourceCompileInstance(projectSource, mHotIdx);
|
|
|
|
if (compileInstance == null)
|
|
|
|
{
|
|
|
|
text = liveText;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text = compileInstance.mSource;
|
|
|
|
|
|
|
|
int32 char8IdStart;
|
|
|
|
int32 char8IdEnd;
|
|
|
|
IdSpan char8IdData = IDEApp.sApp.mWorkspace.GetProjectSourceSelectionCharIds(projectSource, mHotIdx, mDefLineStart, mDefLineEnd, out char8IdStart, out char8IdEnd);
|
|
|
|
if (!char8IdData.IsEmpty)
|
|
|
|
{
|
|
|
|
if (!char8IdData.IsRangeEqual(liveCharIdData, (int32)char8IdStart, (int32)char8IdEnd))
|
|
|
|
{
|
|
|
|
isOld = true;
|
|
|
|
//var sourceEditWidgetContent = (SourceEditWidgetContent)mEditWidget.Content;
|
|
|
|
//sourceEditWidgetContent.SetOldVersionColors(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//var sourceEditWidgetContent = (SourceEditWidgetContent)mEditWidget.Content;
|
|
|
|
//sourceEditWidgetContent.SetOldVersionColors(mHotIdx != -1);
|
|
|
|
|
|
|
|
//app.mWorkspace.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text = scope:: String();
|
|
|
|
if (gApp.LoadTextFile(useFileName, text) case .Err)
|
|
|
|
text = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (text != null)
|
|
|
|
{
|
|
|
|
mCharData = new EditWidgetContent.CharData[text.Length];
|
|
|
|
for (int32 i = 0; i < mCharData.Count; i++)
|
|
|
|
{
|
|
|
|
mCharData[i].mChar = (char8)text[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isBeefSource = IDEApp.IsBeefFile(useFileName);
|
|
|
|
|
|
|
|
var bfSystem = app.mBfResolveSystem;
|
|
|
|
if (bfSystem != null)
|
|
|
|
{
|
|
|
|
//var compiler = app.mBfResolveCompiler;
|
|
|
|
|
|
|
|
BfProject bfProject = null;
|
|
|
|
if (projectSource != null)
|
|
|
|
bfProject = bfSystem.GetBfProject(projectSource.mProject);
|
|
|
|
|
|
|
|
if (text != null)
|
|
|
|
{
|
|
|
|
var parser = bfSystem.CreateEmptyParser(bfProject);
|
|
|
|
var resolvePassData = parser.CreateResolvePassData();
|
|
|
|
var passInstance = bfSystem.CreatePassInstance();
|
|
|
|
|
|
|
|
parser.SetIsClassifying();
|
|
|
|
parser.SetSource(text, useFileName);
|
|
|
|
parser.Parse(passInstance, !isBeefSource);
|
|
|
|
if (isBeefSource)
|
|
|
|
parser.Reduce(passInstance);
|
|
|
|
parser.ClassifySource(mCharData, !isBeefSource);
|
|
|
|
delete resolvePassData;
|
|
|
|
delete parser;
|
|
|
|
delete passInstance;
|
|
|
|
|
|
|
|
mLineStarts = new List<int32>();
|
|
|
|
mLineStarts.Add(0);
|
|
|
|
|
|
|
|
for (int32 i = 0; i < text.Length; i++)
|
|
|
|
if (mCharData[i].mChar == '\n')
|
|
|
|
mLineStarts.Add(i + 1);
|
|
|
|
mLineStarts.Add((int32)text.Length + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*string GetSourceLine(int lineNum)
|
|
|
|
{
|
|
|
|
if (lineNum >= mSourceLines.Length)
|
|
|
|
return null;
|
|
|
|
return mSourceLines[lineNum];
|
|
|
|
}*/
|
|
|
|
|
|
|
|
//////
|
|
|
|
|
|
|
|
public void GoToSource()
|
|
|
|
{
|
|
|
|
if (String.IsNullOrEmpty(mSourceFileName))
|
|
|
|
{
|
|
|
|
IDEApp.sApp.Fail("Unable to locate source");
|
|
|
|
return;
|
|
|
|
}
|
2019-11-22 12:27:13 -08:00
|
|
|
#unwarn
|
2019-08-23 11:56:54 -07:00
|
|
|
var sourceViewPanel = gApp.ShowSourceFileLocation(mSourceFileName, -1, IDEApp.sApp.mWorkspace.GetHighestCompileIdx(), mSourceLine, mSourceColumn, LocatorType.None);
|
2019-11-22 12:27:13 -08:00
|
|
|
if (sourceViewPanel.mLoadFailed)
|
|
|
|
sourceViewPanel.mWantHash = mSourceHash;
|
|
|
|
|
|
|
|
/*if (sourceViewPanel.LoadedHash case .None)
|
|
|
|
sourceViewPanel.LoadedHash = mSourceHash; // Set for when we do Auto Find*/
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public bool SelectLine(int addr, bool jumpToPos)
|
|
|
|
{
|
|
|
|
var editContent = mEditWidget.Content;
|
|
|
|
if (editContent.mData.mLineStarts == null)
|
|
|
|
return false;
|
|
|
|
//FocusEdit();
|
|
|
|
|
|
|
|
for (int32 lineIdx = 0; lineIdx < mLineDatas.Count; lineIdx++)
|
|
|
|
{
|
|
|
|
var lineData = mLineDatas[lineIdx];
|
|
|
|
|
|
|
|
if ((lineData.mAddr != (int)0) && (addr >= lineData.mAddr) && (addr < lineData.mAddrEnd))
|
|
|
|
{
|
|
|
|
if (lineIdx >= editContent.mData.mLineStarts.Count)
|
|
|
|
{
|
|
|
|
// Wtf?
|
|
|
|
editContent.CursorTextPos = editContent.mData.mTextLength;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
editContent.CursorTextPos = editContent.mData.mLineStarts[lineIdx];
|
|
|
|
|
|
|
|
editContent.EnsureCursorVisible(true, true);
|
|
|
|
if (jumpToPos) // Jump to whatever position we're scrolling to
|
|
|
|
{
|
|
|
|
mEditWidget.mVertPos.mPct = 1.0f;
|
|
|
|
mEditWidget.UpdateContentPosition();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int GetCursorAddress(String outSourceFileName)
|
|
|
|
{
|
|
|
|
int line;
|
|
|
|
int lineChar;
|
|
|
|
mEditWidget.Content.GetLineCharAtIdx(mEditWidget.Content.CursorTextPos, out line, out lineChar);
|
|
|
|
line = Math.Min(line, (int32)mLineDatas.Count - 1);
|
|
|
|
|
|
|
|
for (int checkLine = line; checkLine >= 0; checkLine--)
|
|
|
|
{
|
|
|
|
var lineData = mLineDatas[checkLine];
|
|
|
|
if (lineData.mSourceFile != null)
|
|
|
|
{
|
|
|
|
outSourceFileName.Append(lineData.mSourceFile);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int checkLine = line; checkLine < mLineDatas.Count; checkLine++)
|
|
|
|
{
|
|
|
|
var lineData = mLineDatas[checkLine];
|
|
|
|
if (lineData.mAddr != (int)0)
|
|
|
|
return lineData.mAddr;
|
|
|
|
}
|
|
|
|
for (int checkLine = line - 1; checkLine >= 0; checkLine--)
|
|
|
|
{
|
|
|
|
var lineData = mLineDatas[checkLine];
|
|
|
|
if (lineData.mAddr != (int)0)
|
|
|
|
return lineData.mAddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (int)0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*public void Show(int addr, String sourceFile = null, int32 sourceLine = -1, int32 sourceColumn = -1, int32 hotIdx = -1, int32 defLineStart = -1, int32 defLineEnd = -1)
|
|
|
|
{
|
|
|
|
String codeData = scope String();
|
|
|
|
var lines = String.StackSplit!(codeData, '\n');
|
|
|
|
}*/
|
|
|
|
|
|
|
|
void RemovePanelHeader()
|
|
|
|
{
|
|
|
|
if (mStayInDisassemblyCheckbox != null)
|
|
|
|
mStayInDisassemblyCheckbox.RemoveSelf();
|
|
|
|
if (mPanelHeader != null)
|
|
|
|
{
|
|
|
|
mPanelHeader.RemoveSelf();
|
|
|
|
delete mPanelHeader;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Show(int addr, String sourceFile = null, int sourceLine = -1, int sourceColumn = -1, int hotIdx = -1, int defLineStart = -1, int defLineEnd = -1)
|
|
|
|
{
|
|
|
|
if (sourceFile == null)
|
|
|
|
DeleteAndNullify!(mSourceFileName);
|
|
|
|
else
|
|
|
|
String.NewOrSet!(mSourceFileName, sourceFile);
|
|
|
|
mSourceLine = (int32)sourceLine;
|
|
|
|
mSourceColumn = (int32)sourceColumn;
|
|
|
|
mHotIdx = (int32)hotIdx;
|
|
|
|
mDefLineStart = (int32)defLineStart;
|
|
|
|
mDefLineEnd = (int32)defLineEnd;
|
|
|
|
mSourceHash = .();
|
|
|
|
|
|
|
|
if (mParent == null)
|
|
|
|
{
|
|
|
|
mDeferredAddr = addr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mDeferredAddr = 0;
|
|
|
|
|
|
|
|
//bool wasChecked = false;
|
|
|
|
RemovePanelHeader();
|
|
|
|
mPanelHeader = new PanelHeader();
|
|
|
|
mPanelHeader.Label = "Showing disassembly.";
|
|
|
|
|
|
|
|
var font = DarkTheme.sDarkTheme.mSmallFont;
|
|
|
|
if (mStayInDisassemblyCheckbox == null)
|
|
|
|
mStayInDisassemblyCheckbox = new DarkCheckBox();
|
|
|
|
mStayInDisassemblyCheckbox.Label = "Stay in dis&assembly mode.";
|
|
|
|
mStayInDisassemblyCheckbox.Resize(font.GetWidth(mPanelHeader.mLabel) + 30, 6, mStayInDisassemblyCheckbox.CalcWidth(), 20);
|
|
|
|
//if (mStayInDisassemblyCheckbox != null)
|
|
|
|
//checkbox.mChecked = mStayInDisassemblyCheckbox.mChecked;
|
|
|
|
mPanelHeader.AddWidget(mStayInDisassemblyCheckbox);
|
|
|
|
//mStayInDisassemblyCheckbox = checkbox;
|
|
|
|
|
|
|
|
if (!String.IsNullOrEmpty(mSourceFileName))
|
|
|
|
{
|
|
|
|
var button = mPanelHeader.AddButton("Show Sour&ce");
|
|
|
|
button.mOnMouseClick.Add(new (evt) => GoToSource());
|
|
|
|
}
|
|
|
|
AddWidget(mPanelHeader);
|
|
|
|
mIsInitialized = true;
|
|
|
|
ResizeComponents();
|
|
|
|
|
|
|
|
if ((mIsRawDiassembly) && (String.IsNullOrEmpty(sourceFile)))
|
|
|
|
{
|
|
|
|
if (SelectLine(addr, false))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var sourceEditWidgetContent = (SourceEditWidgetContent)mEditWidget.Content;
|
|
|
|
sourceEditWidgetContent.SetOldVersionColors(false);
|
|
|
|
|
|
|
|
Clear();
|
|
|
|
|
|
|
|
mIsRawDiassembly = false;
|
|
|
|
mEditWidget.SetText("");
|
|
|
|
mLineDatas.Clear();
|
|
|
|
|
|
|
|
String codeData = scope String();
|
2019-09-26 08:26:49 -07:00
|
|
|
if (addr != 0)
|
|
|
|
IDEApp.sApp.mDebugger.DisassembleAt(addr, codeData);
|
2019-08-23 11:56:54 -07:00
|
|
|
int prevDisasmLineData = -1;
|
|
|
|
int lineIdx = 0;
|
|
|
|
bool allowEmptyLine = false;
|
|
|
|
bool allowOldColoring = true;
|
|
|
|
|
|
|
|
//var lines = String.StackSplit!(codeData, '\n');
|
|
|
|
|
|
|
|
String line = scope String();
|
|
|
|
//char8[] seps = scope char8[] { '\n' };
|
|
|
|
//for (var lineStrView in codeData.Split(seps))
|
|
|
|
|
|
|
|
int checkIdx = 0;
|
|
|
|
bool hadSourceLines = false;
|
|
|
|
bool isOptimized = false;
|
|
|
|
|
|
|
|
String sourceLineText = scope .(1024);
|
|
|
|
|
|
|
|
for (var lineStrView in codeData.Split('\n'))
|
|
|
|
{
|
|
|
|
checkIdx++;
|
|
|
|
|
|
|
|
line.Reference(lineStrView);
|
|
|
|
if (line.Length == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
int32 prevLen = mEditWidget.Content.mData.mTextLength;
|
|
|
|
int32 typeId = -1;
|
|
|
|
|
|
|
|
LineData lineData = .();
|
|
|
|
bool addLineData = true;
|
|
|
|
bool nextAllowEmptyLine = false;
|
|
|
|
|
|
|
|
switch (line[0])
|
|
|
|
{
|
|
|
|
case 'O':
|
|
|
|
isOptimized = true;
|
|
|
|
addLineData = false;
|
|
|
|
case 'R':
|
|
|
|
mIsRawDiassembly = true;
|
|
|
|
addLineData = false;
|
|
|
|
case 'S':
|
|
|
|
{
|
|
|
|
typeId = (int32)SourceElementType.Disassembly_FileName;
|
|
|
|
String fileName = scope String(line, 2);
|
|
|
|
bool isOld;
|
|
|
|
SetFile(fileName, out isOld);
|
|
|
|
String text = scope String("--- ", fileName);
|
|
|
|
if (isOld)
|
|
|
|
{
|
|
|
|
text.Append(" (old version)");
|
|
|
|
if (allowOldColoring)
|
|
|
|
{
|
|
|
|
sourceEditWidgetContent.SetOldVersionColors(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
allowOldColoring = false;
|
|
|
|
}
|
|
|
|
text.Append("\n");
|
|
|
|
mEditWidget.Content.InsertText(prevLen, text);
|
|
|
|
lineIdx++;
|
|
|
|
}
|
|
|
|
break;
|
2019-11-22 12:27:13 -08:00
|
|
|
case 'H':
|
|
|
|
{
|
|
|
|
mSourceHash = SourceHash.Create(.(line, 2));
|
|
|
|
}
|
2019-08-23 11:56:54 -07:00
|
|
|
case 'T':
|
|
|
|
{
|
|
|
|
typeId = (int32)SourceElementType.Disassembly_FileName;
|
|
|
|
String lineText = scope String(line, 2);
|
|
|
|
lineText.Append("\n");
|
|
|
|
mEditWidget.Content.InsertText(prevLen, lineText);
|
|
|
|
lineIdx++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
{
|
|
|
|
typeId = (int32)SourceElementType.Disassembly_Text;
|
|
|
|
String disasmLine = scope String(line, 2);
|
|
|
|
disasmLine.Append("\n");
|
|
|
|
mEditWidget.Content.InsertText(prevLen, disasmLine);
|
|
|
|
|
|
|
|
int32 parenPos = (int32)disasmLine.IndexOf(':');
|
|
|
|
//int ptrSize = 8;
|
|
|
|
var addrString = scope String(disasmLine, 0, parenPos);
|
|
|
|
addrString.Replace("'", "");
|
|
|
|
lineData.mAddr = (int)int64.Parse(addrString, System.Globalization.NumberStyles.HexNumber);
|
|
|
|
lineData.mAddrEnd = lineData.mAddr + 1;
|
|
|
|
|
|
|
|
if (prevDisasmLineData != -1)
|
|
|
|
{
|
|
|
|
var prevLineData = mLineDatas[prevDisasmLineData];
|
|
|
|
prevLineData.mAddrEnd = lineData.mAddr;
|
|
|
|
mLineDatas[prevDisasmLineData] = prevLineData;
|
|
|
|
}
|
|
|
|
prevDisasmLineData = mLineDatas.Count;
|
|
|
|
|
|
|
|
mAddrLines[lineData.mAddr] = (int32)lineIdx;
|
|
|
|
|
|
|
|
lineIdx++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
{
|
|
|
|
typeId = -1;
|
|
|
|
var itr = line.Split(' ');
|
|
|
|
itr.MoveNext();
|
|
|
|
int32 sourceLineStart = int32.Parse(itr.GetNext());
|
|
|
|
int32 sourceLineCount = int32.Parse(itr.GetNext());
|
|
|
|
|
|
|
|
if ((mLineStarts == null) || (sourceLineStart < 0) || (sourceLineStart + sourceLineCount >= mLineStarts.Count - 1))
|
|
|
|
{
|
|
|
|
//mEditWidget.Content.InsertText(prevLen, "- Error -\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExtractLine(int sourceLineNum, String destString, out int32 startIdx, out int32 endIdx)
|
|
|
|
{
|
|
|
|
destString.Clear();
|
|
|
|
startIdx = mLineStarts[sourceLineNum];
|
|
|
|
endIdx = mLineStarts[sourceLineNum + 1] - 1;
|
|
|
|
char8[] chars = scope char8[endIdx - startIdx];
|
|
|
|
for (int32 idx = startIdx; idx < endIdx; idx++)
|
|
|
|
chars[idx - startIdx] = (char8)mCharData[idx].mChar;
|
|
|
|
destString.Append(chars, 0, chars.Count);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ((!hadSourceLines) && (!isOptimized))
|
|
|
|
{
|
|
|
|
// Try to trim off the bottom of the preceding method
|
|
|
|
for (int32 checkLine = sourceLineStart + sourceLineCount - 2; checkLine >= sourceLineStart; checkLine--)
|
|
|
|
{
|
|
|
|
ExtractLine(checkLine, sourceLineText, var startIdx, var endIdx);
|
|
|
|
|
|
|
|
if ((sourceLineText.Contains("}")) || (sourceLineText.Contains(";")))
|
|
|
|
{
|
|
|
|
int32 offset = checkLine - sourceLineStart + 1;
|
|
|
|
sourceLineStart += offset;
|
|
|
|
sourceLineCount -= offset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int32 sourceLineNum = sourceLineStart; sourceLineNum < sourceLineStart + sourceLineCount; sourceLineNum++)
|
|
|
|
{
|
|
|
|
//int32 startIdx;
|
|
|
|
//int32 endIdx;
|
|
|
|
ExtractLine(sourceLineNum, sourceLineText, var startIdx, var endIdx);
|
|
|
|
if ((!allowEmptyLine) && (sourceLineText.IsWhiteSpace))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
allowEmptyLine = true;
|
|
|
|
sourceLineText.Append("\n");
|
|
|
|
prevLen = mEditWidget.Content.mData.mTextLength;
|
|
|
|
mEditWidget.Content.InsertText(prevLen, sourceLineText);
|
|
|
|
for (int32 i = 0; i < endIdx - startIdx; i++)
|
|
|
|
mEditWidget.Content.mData.mText[i + prevLen].mDisplayTypeId = mCharData[i + startIdx].mDisplayTypeId;
|
|
|
|
|
|
|
|
lineData = .();
|
|
|
|
lineData.mSourceFile = mDiasmSourceFileName;
|
|
|
|
lineData.mSourceLineNum = sourceLineNum;
|
|
|
|
lineIdx++;
|
|
|
|
|
|
|
|
mLineDatas.Add(lineData);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Just about the only case we allow an empty line is when it occurs after a non-empty source line
|
|
|
|
nextAllowEmptyLine = true;
|
|
|
|
addLineData = false;
|
|
|
|
hadSourceLines = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'J':
|
|
|
|
{
|
|
|
|
addLineData = false;
|
|
|
|
JumpEntry jumpEntry = new JumpEntry();
|
|
|
|
int64 addrFrom = (int64)mLineDatas[mLineDatas.Count - 1].mAddr;
|
|
|
|
int64 addrTo = int64.Parse(scope String(line, 2), System.Globalization.NumberStyles.HexNumber);
|
|
|
|
jumpEntry.mAddrMin = (int)Math.Min(addrFrom, addrTo);
|
|
|
|
jumpEntry.mAddrMax = (int)Math.Max(addrFrom, addrTo);
|
|
|
|
jumpEntry.mIsReverse = jumpEntry.mAddrMin == (int)addrTo;
|
|
|
|
jumpEntry.mDepth = -1;
|
|
|
|
|
|
|
|
if (jumpEntry.mAddrMin != jumpEntry.mAddrMax)
|
|
|
|
mJumpTable.Add(jumpEntry);
|
|
|
|
else
|
|
|
|
delete jumpEntry;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
allowEmptyLine = nextAllowEmptyLine;
|
|
|
|
|
|
|
|
if (addLineData)
|
|
|
|
{
|
|
|
|
mLineDatas.Add(lineData);
|
|
|
|
|
|
|
|
if (typeId != -1)
|
|
|
|
{
|
|
|
|
for (int32 i = prevLen; i <= mEditWidget.Content.mData.mTextLength; i++)
|
|
|
|
mEditWidget.Content.mData.mText[i].mDisplayTypeId = (uint8)typeId;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mJumpTable.Sort(scope (a, b) =>
|
|
|
|
{
|
|
|
|
int32 diff = (int32)((a.mAddrMax - a.mAddrMin) - (b.mAddrMax - b.mAddrMin));
|
|
|
|
if (diff != 0)
|
|
|
|
return diff;
|
|
|
|
return (int32)(a.mAddrMin - b.mAddrMin);
|
|
|
|
});
|
|
|
|
|
|
|
|
List<int32> arrowDepths = scope List<int32>();
|
|
|
|
for (int32 jumpIdx = 0; jumpIdx < mJumpTable.Count; jumpIdx++)
|
|
|
|
{
|
|
|
|
var jumpEntry = mJumpTable[jumpIdx];
|
|
|
|
|
|
|
|
arrowDepths.Clear();
|
|
|
|
for (int32 checkJumpIdx = 0; checkJumpIdx < mJumpTable.Count; checkJumpIdx++)
|
|
|
|
{
|
|
|
|
var checkJumpEntry = mJumpTable[checkJumpIdx];
|
|
|
|
if ((checkJumpEntry.mDepth != -1) &&
|
|
|
|
(((checkJumpEntry.mAddrMin > jumpEntry.mAddrMin) && (checkJumpEntry.mAddrMin < jumpEntry.mAddrMax)) ||
|
|
|
|
((checkJumpEntry.mAddrMax > jumpEntry.mAddrMin) && (checkJumpEntry.mAddrMax < jumpEntry.mAddrMax))))
|
|
|
|
arrowDepths.Add(checkJumpEntry.mDepth);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int32 checkDepth = 0; true; checkDepth++)
|
|
|
|
{
|
|
|
|
if (!arrowDepths.Contains(checkDepth))
|
|
|
|
{
|
|
|
|
jumpEntry.mDepth = checkDepth;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int32 checkJumpIdx = 0; checkJumpIdx < mJumpTable.Count; checkJumpIdx++)
|
|
|
|
{
|
|
|
|
var checkJumpEntry = mJumpTable[checkJumpIdx];
|
|
|
|
if ((checkJumpEntry.mDepth == -1) || (checkJumpEntry.mDepth >= jumpEntry.mDepth))
|
|
|
|
continue;
|
|
|
|
if ((jumpEntry.mAddrMin > checkJumpEntry.mAddrMin) && (jumpEntry.mAddrMin < checkJumpEntry.mAddrMax))
|
|
|
|
jumpEntry.mOverlapsAtMin.Add(checkJumpEntry.mDepth);
|
|
|
|
if ((jumpEntry.mAddrMax > checkJumpEntry.mAddrMin) && (jumpEntry.mAddrMax < checkJumpEntry.mAddrMax))
|
|
|
|
jumpEntry.mOverlapsAtMax.Add(checkJumpEntry.mDepth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mEditWidget.Content.ClampCursor();
|
|
|
|
mEditWidget.Content.ContentChanged();
|
|
|
|
mEditWidget.Content.RecalcSize();
|
|
|
|
|
|
|
|
//Debug.Assert(mLineDatas.Count == mEditWidget.Content.mLineStarts.Length);
|
|
|
|
|
|
|
|
SelectLine(addr, true);
|
|
|
|
// Go there immediately
|
|
|
|
mEditWidget.mVertPos.mPct = 1.0f;
|
|
|
|
mEditWidget.UpdateContentPosition();
|
|
|
|
|
|
|
|
if (mEditWidget.Content.mData.mTextLength == 0)
|
|
|
|
{
|
|
|
|
mEditWidget.SetText("Disassembly unavailable");
|
|
|
|
}
|
|
|
|
|
|
|
|
//mEditWidget.Text = codeData;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void Draw(Beefy.gfx.Graphics g)
|
|
|
|
{
|
|
|
|
base.Draw(g);
|
|
|
|
|
|
|
|
DarkEditWidgetContent darkEditWidgetContent = (DarkEditWidgetContent)mEditWidget.Content;
|
|
|
|
|
|
|
|
g.SetFont(IDEApp.sApp.mTinyCodeFont);
|
|
|
|
|
|
|
|
int curCallStackAddr = 0;
|
|
|
|
int32 jmpState = -1;
|
|
|
|
if (IDEApp.sApp.mExecutionPaused)
|
|
|
|
{
|
|
|
|
String fileName = null;
|
|
|
|
IDEApp.sApp.mDebugger.GetStackFrameInfo(IDEApp.sApp.mDebugger.mActiveCallStackIdx, out curCallStackAddr, fileName, null);
|
|
|
|
|
|
|
|
jmpState = IDEApp.sApp.mDebugger.GetJmpState(IDEApp.sApp.mDebugger.mActiveCallStackIdx);
|
|
|
|
}
|
|
|
|
|
|
|
|
mBreakpointAddrs.Clear();
|
|
|
|
for (var breakpoint in IDEApp.sApp.mDebugger.mBreakpointList)
|
|
|
|
{
|
|
|
|
void* curBreakpointItr = null;
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
int addr = breakpoint.GetAddress(ref curBreakpointItr);
|
|
|
|
if (addr != (int)0)
|
|
|
|
mBreakpointAddrs.TryAdd(addr, breakpoint);
|
|
|
|
if (curBreakpointItr == null)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String callstackFileName = scope String(Path.MaxPath);
|
|
|
|
int callstackLineNum = -1;
|
|
|
|
|
|
|
|
Image linePointerImage = DarkTheme.sDarkTheme.GetImage(.LinePointer);
|
|
|
|
if (IDEApp.sApp.mExecutionPaused)
|
|
|
|
{
|
|
|
|
int addr;
|
|
|
|
|
|
|
|
int hotIdx;
|
|
|
|
int defLineStart;
|
|
|
|
int defLineEnd;
|
|
|
|
//int lineNum;
|
|
|
|
int column;
|
|
|
|
int language;
|
|
|
|
int stackSize;
|
|
|
|
DebugManager.FrameFlags frameFlags;
|
|
|
|
IDEApp.sApp.mDebugger.GetStackFrameInfo(IDEApp.sApp.mDebugger.mActiveCallStackIdx, null, out addr, callstackFileName, out hotIdx, out defLineStart, out defLineEnd, out callstackLineNum, out column, out language, out stackSize, out frameFlags);
|
|
|
|
int hashPos = callstackFileName.IndexOf('#');
|
|
|
|
if (hashPos != -1)
|
|
|
|
callstackFileName.RemoveToEnd(hashPos);
|
|
|
|
if (frameFlags.HasFlag(.Optimized))
|
|
|
|
linePointerImage = DarkTheme.sDarkTheme.GetImage(.LinePointer_Opt);
|
|
|
|
//IDEUtils.FixFilePath(fileName);
|
|
|
|
|
|
|
|
if (IDEApp.sApp.mDebugger.mActiveCallStackIdx == 0)
|
|
|
|
callstackLineNum = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//jmpState = 0;
|
|
|
|
var disasmEditContent = (DisassemblyEditContent)mEditWidget.Content;
|
|
|
|
disasmEditContent.mJmpState = -1;
|
|
|
|
|
|
|
|
using (g.PushClip(0, 0, mWidth, mHeight))
|
|
|
|
{
|
|
|
|
using (g.PushTranslate(0, mEditWidget.mY + mEditWidget.Content.Y))
|
|
|
|
{
|
|
|
|
float lineSpacing = darkEditWidgetContent.mFont.GetLineSpacing();
|
|
|
|
|
|
|
|
int lineStart = Math.Max(0, (int32)((-mEditWidget.Content.Y) / lineSpacing) - 1);
|
|
|
|
int lineEnd = Math.Min(mLineDatas.Count, lineStart + (int32)(mHeight / lineSpacing) + 3);
|
|
|
|
|
|
|
|
using (g.PushColor(0x80FFFFFF))
|
|
|
|
{
|
|
|
|
for (int lineIdx = lineStart; lineIdx < lineEnd; lineIdx++)
|
|
|
|
{
|
|
|
|
var lineData = mLineDatas[lineIdx];
|
|
|
|
if (lineData.mSourceFile != null)
|
|
|
|
g.DrawString(StackStringFormat!("{0}", lineData.mSourceLineNum + 1), 8, 2 + lineIdx * lineSpacing, FontAlign.Right, 18);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int lineIdx = lineStart; lineIdx < lineEnd; lineIdx++)
|
|
|
|
{
|
|
|
|
var lineData = mLineDatas[lineIdx];
|
|
|
|
|
|
|
|
if ((lineData.mAddr != (int)0) && (mBreakpointAddrs.GetValue(lineData.mAddr) case .Ok(let breakpoint)))
|
|
|
|
{
|
|
|
|
//g.Draw(DarkTheme.sDarkTheme.GetImage(.RedDot), mEditWidget.mX - 20,
|
|
|
|
//0 + lineIdx * lineSpacing);
|
|
|
|
using (g.PushTranslate(mEditWidget.mX - 20, 0 + lineIdx * lineSpacing))
|
|
|
|
breakpoint.Draw(g, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((lineData.mAddr != (int)0) && (curCallStackAddr >= lineData.mAddr) && (curCallStackAddr < lineData.mAddrEnd))
|
|
|
|
{
|
|
|
|
Image img = (IDEApp.sApp.mDebugger.mActiveCallStackIdx == 0) ? linePointerImage : DarkTheme.sDarkTheme.GetImage(.ReturnPointer);
|
|
|
|
g.Draw(img, mEditWidget.mX - 20,
|
|
|
|
0 + lineIdx * lineSpacing);
|
|
|
|
|
|
|
|
/*if (jmpState != -1)
|
|
|
|
{
|
|
|
|
img = (jmpState == 0) ? DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.NoJmp) : DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.YesJmp);
|
|
|
|
g.Draw(img, mEditWidget.mX + 20,
|
|
|
|
0 + lineIdx * lineSpacing);
|
|
|
|
}*/
|
|
|
|
disasmEditContent.mJmpState = jmpState;
|
|
|
|
disasmEditContent.mJmpIconY = -4 + lineIdx * lineSpacing;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((lineData.mSourceFile != null) && (lineData.mSourceLineNum == callstackLineNum) && (Path.Equals(lineData.mSourceFile, callstackFileName)))
|
|
|
|
{
|
|
|
|
//RemapCompiledToActiveLine(hotIdx, ref lineNum, ref column);
|
|
|
|
Image img = (IDEApp.sApp.mDebugger.mActiveCallStackIdx == 0) ? linePointerImage : DarkTheme.sDarkTheme.GetImage(.LinePointer_Prev);
|
|
|
|
g.Draw(img, mEditWidget.mX - 20,
|
|
|
|
0 + lineIdx * lineSpacing);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*public IEnumerable<T> FindTrackedElementsAtCursor<T>(List<T> trackedElementList) where T : TrackedTextElement
|
|
|
|
{
|
|
|
|
int lineIdx;
|
|
|
|
int lineCharIdx;
|
|
|
|
mEditWidget.Content.GetLineCharAtIdx(mEditWidget.Content.CursorTextPos, out lineIdx, out lineCharIdx);
|
|
|
|
|
|
|
|
int idx = 0;
|
|
|
|
while (idx < trackedElementList.Count)
|
|
|
|
{
|
|
|
|
var trackedElement = trackedElementList[idx];
|
|
|
|
if (trackedElement.mLineNum == lineIdx)
|
|
|
|
{
|
|
|
|
int prevSize = trackedElementList.Count;
|
|
|
|
yield return trackedElement;
|
|
|
|
if (trackedElementList.Count >= prevSize)
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
|
|
|
|
// This is useful for a one-shot breakpoint within the current execution context- IE: "Run to cursor"
|
2019-12-13 14:25:15 -08:00
|
|
|
public Breakpoint ToggleAddrBreakpointAtCursor(Breakpoint.SetKind setKind = .Toggle, Breakpoint.SetFlags flags = .None, int threadId = -1)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
DebugManager debugManager = IDEApp.sApp.mDebugger;
|
|
|
|
|
|
|
|
int lineIdx;
|
|
|
|
int lineCharIdx;
|
|
|
|
mEditWidget.Content.GetLineCharAtIdx(mEditWidget.Content.CursorTextPos, out lineIdx, out lineCharIdx);
|
|
|
|
|
|
|
|
int checkIdx = lineIdx;
|
|
|
|
LineData lineData = mLineDatas[checkIdx];
|
|
|
|
|
|
|
|
if (lineData.mAddr == (int)0)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
bool hadBreakpoint = false;
|
2019-12-13 14:25:15 -08:00
|
|
|
if (setKind != .Force)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
for (int32 breakIdx = 0; breakIdx < IDEApp.sApp.mDebugger.mBreakpointList.Count; breakIdx++)
|
|
|
|
{
|
|
|
|
var breakpoint = IDEApp.sApp.mDebugger.mBreakpointList[breakIdx];
|
|
|
|
if (breakpoint.ContainsAddress(lineData.mAddr))
|
|
|
|
{
|
|
|
|
hadBreakpoint = true;
|
|
|
|
BfLog.LogDbg("DisassemblyPanel.ToggleAddrBreakpointAtCursor\n");
|
|
|
|
debugManager.DeleteBreakpoint(breakpoint);
|
|
|
|
breakIdx--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hadBreakpoint)
|
|
|
|
{
|
|
|
|
var editWidgetContent = mEditWidget.Content;
|
|
|
|
int textPos = mEditWidget.Content.CursorTextPos - lineCharIdx;
|
|
|
|
lineCharIdx = 0;
|
|
|
|
|
|
|
|
// Find first non-space char8
|
|
|
|
while ((textPos < editWidgetContent.mData.mTextLength) && (((char8)editWidgetContent.mData.mText[textPos].mChar).IsWhiteSpace))
|
|
|
|
{
|
|
|
|
textPos++;
|
|
|
|
lineCharIdx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
let breakpoint = debugManager.CreateBreakpoint(lineData.mAddr);
|
|
|
|
breakpoint.SetThreadId(threadId);
|
|
|
|
return breakpoint;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-12-13 14:25:15 -08:00
|
|
|
public Breakpoint ToggleBreakpointAtCursor(Breakpoint.SetKind setKind = .Toggle, Breakpoint.SetFlags flags = .None, int threadId = -1)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
DebugManager debugManager = IDEApp.sApp.mDebugger;
|
|
|
|
|
|
|
|
int lineIdx;
|
|
|
|
int lineCharIdx;
|
|
|
|
mEditWidget.Content.GetLineCharAtIdx(mEditWidget.Content.CursorTextPos, out lineIdx, out lineCharIdx);
|
|
|
|
|
|
|
|
int checkIdx = lineIdx;
|
|
|
|
int instrOffsetCount = -1;
|
|
|
|
LineData lineData;
|
|
|
|
if (checkIdx >= mLineDatas.Count)
|
|
|
|
return null;
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
if (checkIdx < 0)
|
|
|
|
{
|
2019-12-13 14:25:15 -08:00
|
|
|
return ToggleAddrBreakpointAtCursor(setKind, flags, threadId);
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
lineData = mLineDatas[checkIdx];
|
|
|
|
if (lineData.mSourceFile != null)
|
|
|
|
{
|
|
|
|
bool foundOrigin = false;
|
|
|
|
|
|
|
|
// In the case of a split line (ie: a method call that contains an inlined method call as a param),
|
|
|
|
// we search for the first instance of this line
|
|
|
|
for (int originIdx = 0; originIdx <= lineIdx; originIdx++)
|
|
|
|
{
|
|
|
|
var originLineData = mLineDatas[originIdx];
|
|
|
|
if ((originLineData.mSourceFile != null) && (originLineData.mSourceFile == lineData.mSourceFile) && (originLineData.mSourceLineNum == lineData.mSourceLineNum))
|
|
|
|
{
|
|
|
|
foundOrigin = true;
|
|
|
|
}
|
|
|
|
else if ((foundOrigin) && (originLineData.mAddr != 0))
|
|
|
|
{
|
|
|
|
instrOffsetCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
checkIdx--;
|
|
|
|
}
|
|
|
|
|
|
|
|
//We DO need to allow "+0", otherwise we can't bind to the PRELUDE of a function
|
|
|
|
// Is there any reason to allow explicitly binding to "+0"?
|
|
|
|
/*if (instrOffsetCount == 0)
|
|
|
|
instrOffsetCount = -1;*/
|
|
|
|
|
|
|
|
bool hadBreakpoint = false;
|
2019-12-13 14:25:15 -08:00
|
|
|
if (setKind != .Force)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
for (int32 breakIdx = 0; breakIdx < IDEApp.sApp.mDebugger.mBreakpointList.Count; breakIdx++)
|
|
|
|
{
|
|
|
|
var breakpoint = IDEApp.sApp.mDebugger.mBreakpointList[breakIdx];
|
|
|
|
if ((breakpoint.mFileName != null) && (Path.Equals(breakpoint.mFileName, lineData.mSourceFile)) && (breakpoint.mLineNum == lineData.mSourceLineNum) &&
|
|
|
|
(Math.Max(0, breakpoint.mInstrOffset) == Math.Max(0, instrOffsetCount)))
|
|
|
|
{
|
|
|
|
hadBreakpoint = true;
|
|
|
|
BfLog.LogDbg("DisassemblyPanel.ToggleBreakpointAtCursor deleting breakpoint\n");
|
|
|
|
debugManager.DeleteBreakpoint(breakpoint);
|
|
|
|
breakIdx--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hadBreakpoint)
|
|
|
|
{
|
|
|
|
var editWidgetContent = mEditWidget.Content;
|
|
|
|
int textPos = mEditWidget.Content.CursorTextPos - lineCharIdx;
|
|
|
|
lineCharIdx = 0;
|
|
|
|
|
|
|
|
// Find first non-space char8
|
|
|
|
while ((textPos < editWidgetContent.mData.mTextLength) && (((char8)editWidgetContent.mData.mText[textPos].mChar).IsWhiteSpace))
|
|
|
|
{
|
|
|
|
textPos++;
|
|
|
|
lineCharIdx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
let breakpoint = debugManager.CreateBreakpoint_Create(lineData.mSourceFile, lineData.mSourceLineNum, 0, instrOffsetCount);
|
|
|
|
breakpoint.SetThreadId(threadId);
|
|
|
|
debugManager.CreateBreakpoint_Finish(breakpoint);
|
|
|
|
return breakpoint;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void Clear()
|
|
|
|
{
|
|
|
|
mEditWidget.SetText("");
|
|
|
|
mLineDatas.Clear();
|
|
|
|
ClearAndDeleteItems(mJumpTable);
|
|
|
|
mAddrLines.Clear();
|
|
|
|
mBreakpointAddrs.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Disable()
|
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
mEditWidget.SetText("Disassembly is only available while debugging");
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool Show(String file, int lineNum, int column)
|
2019-11-22 12:27:13 -08:00
|
|
|
{
|
2019-08-23 11:56:54 -07:00
|
|
|
String addrs = scope String();
|
|
|
|
IDEApp.sApp.mDebugger.FindCodeAddresses(file, lineNum, column, true, addrs);
|
|
|
|
if (addrs.Length == 0)
|
|
|
|
{
|
|
|
|
IDEApp.sApp.Fail("Unable to locate code address");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var addrEntries = String.StackSplit!(addrs, '\n');
|
|
|
|
for (var addrEntry in addrEntries)
|
|
|
|
{
|
|
|
|
if (addrEntry.Length == 0)
|
|
|
|
break;
|
|
|
|
var addrData = String.StackSplit!(addrEntry, '\t');
|
|
|
|
int addr = (int)int64.Parse(addrData[0], System.Globalization.NumberStyles.HexNumber);
|
|
|
|
Show(addr, file, lineNum, column);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void AddedToParent()
|
|
|
|
{
|
|
|
|
var app = IDEApp.sApp;
|
|
|
|
|
|
|
|
if (!app.mDebugger.IsPaused())
|
|
|
|
mDeferredAddr = (int)0;
|
|
|
|
if (mDeferredAddr != (int)0)
|
|
|
|
Show(mDeferredAddr, mSourceFileName, mSourceLine, mSourceColumn, mHotIdx, mDefLineStart, mDefLineEnd);
|
|
|
|
|
|
|
|
app.AddToRecentDisplayedFilesList(sPanelName);
|
|
|
|
//IDEApp.sApp.SetInDisassemblyView(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void RemovedFromParent(Widget previousParent, WidgetWindow window)
|
|
|
|
{
|
|
|
|
base.RemovedFromParent(previousParent, window);
|
|
|
|
IDEApp.sApp.SetInDisassemblyView(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void ResizeComponents()
|
|
|
|
{
|
|
|
|
base.ResizeComponents();
|
|
|
|
if (mPanelHeader != null)
|
|
|
|
mPanelHeader.Resize(30, 0, Math.Max(mWidth - 30, 0), 32);
|
|
|
|
mEditWidget.Resize(30, 32, Math.Max(mWidth - 30, 0), Math.Max(mHeight - 32, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void Resize(float x, float y, float width, float height)
|
|
|
|
{
|
|
|
|
base.Resize(x, y, width, height);
|
|
|
|
ResizeComponents();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void UpdateMouseover()
|
|
|
|
{
|
|
|
|
if (!CheckAllowHoverWatch())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (IDEApp.sApp.HasPopupMenus())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((mHoverWatch != null) && (mHoverWatch.mCloseDelay > 0))
|
|
|
|
return;
|
|
|
|
|
|
|
|
var editWidgetContent = mEditWidget.Content;
|
|
|
|
Point mousePos;
|
|
|
|
bool mouseoverFired = DarkTooltipManager.CheckMouseover(editWidgetContent, 10, out mousePos);
|
|
|
|
//CompilerBase compiler = ResolveCompiler;
|
|
|
|
if ((mouseoverFired) || (mHoverWatch != null))
|
|
|
|
{
|
|
|
|
var content = mEditWidget.Content;
|
|
|
|
//int cursorPos = content.CursorTextPos;
|
|
|
|
int line;
|
|
|
|
int lineChar;
|
|
|
|
float overflowX;
|
|
|
|
content.GetLineCharAtCoord(mousePos.x, mousePos.y, out line, out lineChar, out overflowX);
|
|
|
|
int cursorPos = content.GetTextIdx(line, lineChar);
|
|
|
|
|
|
|
|
int leftIdx = -1;
|
|
|
|
int rightIdx = -1;
|
|
|
|
String debugExpr = null;
|
|
|
|
|
|
|
|
if ((cursorPos < content.mData.mTextLength) && (!((char8)content.mData.mText[cursorPos].mChar).IsWhiteSpace))
|
|
|
|
{
|
|
|
|
var typeId = content.mData.mText[cursorPos].mDisplayTypeId;
|
|
|
|
if (typeId == (uint8)SourceElementType.Disassembly_Text)
|
|
|
|
{
|
|
|
|
int lineStart;
|
|
|
|
int lineEnd;
|
|
|
|
content.GetLinePosition(line, out lineStart, out lineEnd);
|
|
|
|
|
|
|
|
String lineStr = scope String();
|
|
|
|
content.ExtractString(lineStart, lineEnd - lineStart, lineStr);
|
|
|
|
int strIdx = 0;
|
|
|
|
|
|
|
|
int colonPos = -1;
|
|
|
|
int instrStartIdx = -1;
|
|
|
|
int instrEndIdx = -1;
|
|
|
|
int firstParamIdx = -1;
|
|
|
|
int commaIdx = -1;
|
|
|
|
|
|
|
|
for (; strIdx < lineStr.Length; strIdx++)
|
|
|
|
{
|
|
|
|
char8 c = lineStr[strIdx];
|
|
|
|
if (colonPos == -1)
|
|
|
|
{
|
|
|
|
if (c == ':')
|
|
|
|
colonPos = strIdx;
|
|
|
|
}
|
|
|
|
else if (instrStartIdx == -1)
|
|
|
|
{
|
|
|
|
if (c.IsLower)
|
|
|
|
instrStartIdx = strIdx;
|
|
|
|
}
|
|
|
|
else if (instrEndIdx == -1)
|
|
|
|
{
|
|
|
|
if (c.IsWhiteSpace)
|
|
|
|
instrEndIdx = strIdx;
|
|
|
|
}
|
|
|
|
else if (firstParamIdx == -1)
|
|
|
|
{
|
|
|
|
if (!c.IsWhiteSpace)
|
|
|
|
firstParamIdx = strIdx;
|
|
|
|
}
|
|
|
|
else if (commaIdx == -1)
|
|
|
|
{
|
|
|
|
if (c == ',')
|
|
|
|
commaIdx = strIdx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int cursorStrIdx = cursorPos - lineStart;
|
|
|
|
if (cursorStrIdx > commaIdx)
|
|
|
|
{
|
|
|
|
if (commaIdx != -1)
|
|
|
|
leftIdx = lineStart + commaIdx + 1;
|
|
|
|
else
|
|
|
|
leftIdx = lineStart + firstParamIdx;
|
|
|
|
rightIdx = lineEnd - 1;
|
|
|
|
}
|
|
|
|
else if (cursorStrIdx >= firstParamIdx)
|
|
|
|
{
|
|
|
|
leftIdx = lineStart + firstParamIdx;
|
|
|
|
if (commaIdx != -1)
|
|
|
|
rightIdx = lineStart + commaIdx - 1;
|
|
|
|
else
|
|
|
|
rightIdx = lineEnd - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (leftIdx != -1)
|
|
|
|
{
|
|
|
|
debugExpr = scope:: String();
|
|
|
|
content.ExtractString(leftIdx, rightIdx - leftIdx + 1, debugExpr);
|
2019-12-13 14:25:15 -08:00
|
|
|
int commaPos = debugExpr.LastIndexOf(',');
|
|
|
|
if (commaPos != -1)
|
|
|
|
debugExpr.RemoveToEnd(commaPos);
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
int32 semiPos = (int32)debugExpr.IndexOf(';');
|
|
|
|
if (semiPos != -1)
|
|
|
|
debugExpr.RemoveToEnd(semiPos);
|
|
|
|
|
|
|
|
debugExpr.Replace('[', '(');
|
|
|
|
debugExpr.Replace(']', ')');
|
2019-09-26 08:26:49 -07:00
|
|
|
debugExpr.Replace("xmmword ptr", "(int64[2]*)");
|
2019-08-23 11:56:54 -07:00
|
|
|
debugExpr.Replace("qword ptr", "(int64*)");
|
|
|
|
debugExpr.Replace("dword ptr", "(int32*)");
|
|
|
|
debugExpr.Replace("word ptr", "(int16*)");
|
|
|
|
debugExpr.Replace("byte ptr", "(int8*)");
|
|
|
|
|
|
|
|
if (line < mLineDatas.Count - 1)
|
|
|
|
{
|
|
|
|
if (mLineDatas[line].mAddrEnd != (int)0)
|
|
|
|
{
|
|
|
|
String nextAddr = StackStringFormat!("0x{0:x}L", (int64)mLineDatas[line].mAddrEnd);
|
|
|
|
nextAddr.Append(" +");
|
|
|
|
debugExpr.Replace("rip +", nextAddr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (commaIdx != -1)
|
|
|
|
{
|
|
|
|
String firstParam = lineStr;
|
|
|
|
semiPos = (int32)lineStr.IndexOf(';');
|
|
|
|
if (semiPos != -1)
|
|
|
|
debugExpr = scope:: String(lineStr, 0, semiPos);
|
|
|
|
|
|
|
|
if (firstParam.Contains("xmm"))
|
|
|
|
{
|
|
|
|
debugExpr.Replace("(int64*)", "(double*)");
|
|
|
|
debugExpr.Replace("(int32*)", "(float*)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((typeId != (uint8)SourceElementType.Comment) && (typeId != (uint8)SourceElementType.Literal))
|
|
|
|
{
|
|
|
|
leftIdx = cursorPos;
|
|
|
|
rightIdx = cursorPos;
|
|
|
|
|
|
|
|
while (leftIdx > 0)
|
|
|
|
{
|
|
|
|
int checkIdx = leftIdx - 1;
|
|
|
|
char8 c = (char8)content.mData.mText[checkIdx].mChar;
|
|
|
|
if ((!c.IsLetterOrDigit) && (c != '.'))
|
|
|
|
break;
|
|
|
|
leftIdx = checkIdx;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (rightIdx < content.mData.mTextLength)
|
|
|
|
{
|
|
|
|
int checkIdx = rightIdx + 1;
|
|
|
|
char8 c = (char8)content.mData.mText[checkIdx].mChar;
|
|
|
|
if ((!c.IsLetterOrDigit) && (c != '.'))
|
|
|
|
break;
|
|
|
|
rightIdx = checkIdx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (leftIdx != -1)
|
|
|
|
{
|
|
|
|
content.GetLineCharAtIdx(leftIdx, out line, out lineChar);
|
|
|
|
float x;
|
|
|
|
float y;
|
|
|
|
editWidgetContent.GetTextCoordAtLineChar(line, lineChar, out x, out y);
|
|
|
|
x = mousePos.x;
|
|
|
|
|
|
|
|
if (debugExpr == null)
|
|
|
|
{
|
|
|
|
debugExpr = scope:: String();
|
|
|
|
content.ExtractString(leftIdx, rightIdx - leftIdx + 1, debugExpr);
|
|
|
|
}
|
|
|
|
if ((mHoverWatch == null) || (mHoverWatch.mEvalString != debugExpr))
|
|
|
|
{
|
|
|
|
if (mHoverWatch != null)
|
|
|
|
{
|
|
|
|
mHoverWatch.Close();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mHoverWatch = new HoverWatch();
|
|
|
|
if (mHoverWatch.Show(this, x, y, debugExpr))
|
|
|
|
{
|
|
|
|
mHoverWatch.mOpenMousePos = DarkTooltipManager.sLastRelMousePos;
|
|
|
|
mHoverWatch.mEvalString.Set(debugExpr); // Set to old debugStr for comparison
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mHoverWatch.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mHoverWatch != null)
|
|
|
|
{
|
|
|
|
mHoverWatch.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void Update()
|
|
|
|
{
|
|
|
|
base.Update();
|
|
|
|
if (mEditWidget.mHasFocus)
|
|
|
|
IDEApp.sApp.SetInDisassemblyView(true);
|
|
|
|
UpdateMouseover();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|