southpolenator / sharpdebug Goto Github PK
View Code? Open in Web Editor NEWC# debugging automation tool
License: MIT License
C# debugging automation tool
License: MIT License
AppVeyor shouldn't upload VSIX for builds unless it was pull request on master or next branch.
Currently, we provide only instructionOffset to IClrThread.GetClrStackFrame, but that is not enough to distinguish a stack frame (recursion for example).
When you load a ELF module that doesn't have Dwarf debug information, but does have exported public functions
(Like for example libpthread that you load when trying to analyze a core dump)
These functions are not considered when trying to look up a function name by instruction pointer.
But it works perfectly fine if you consider them.
I know this is not the proper way to do it, but I want to note it here in case someone who can do it properly comes along.
Add
public PublicSymbol(string name, ulong address, ELFSharp.ELF.Sections.SymbolType type, ulong size)
{
Name = name;
Address = address;
demangledName = SimpleCache.Create(() => Demangle(name));
Type = type;
Size = size;
}
public ELFSharp.ELF.Sections.SymbolType Type { get; private set; }
public ulong Size { get; private set; }
and
publicSymbols.Add(new PublicSymbol(symbol.Name, symbol.Value - CodeSegmentOffset,symbol.Type, symbol.Size));
and (this is the most hacky part)
functionsCache.AddRange(
publicSymbols
.Where(x => x.Type == SymbolType.Function && x.Size != 0 && x.Address != 0)
.Where(x =>
functionsCache.All(f =>
f.GetConstantAttribute(DwarfAttribute.LowPc) != x.Address) // #TODO binary search
).Select(publicSymbol =>
{
Dictionary<DwarfAttribute, DwarfAttributeValue> attributes = new Dictionary<DwarfAttribute, DwarfAttributeValue>();
attributes.Add(DwarfAttribute.Name, new DwarfAttributeValue() { Type = DwarfAttributeValueType.String, Value = publicSymbol.Name });
// LowPC is function start
attributes.Add(DwarfAttribute.LowPc, new DwarfAttributeValue() { Type = DwarfAttributeValueType.Address, Value = publicSymbol.Address });
// HighPc can either be address (end address) or constant (offset after start address, function size)
attributes.Add(DwarfAttribute.HighPc, new DwarfAttributeValue() { Type = DwarfAttributeValueType.Constant, Value = publicSymbol.Size });
attributes.Add(DwarfAttribute.ByteSize, new DwarfAttributeValue() { Type = DwarfAttributeValueType.Constant, Value = publicSymbol.Size });
attributes.Add(DwarfAttribute.Type, new DwarfAttributeValue() { Type = DwarfAttributeValueType.Constant, Value = publicSymbol.Size });
return new DwarfSymbol { Tag = DwarfTag.Subprogram, Attributes = attributes };
})
);
After these changes you will be able to resolve function names in libraries without debugging info.
Measure number of packets sent to DPE and decrease them. Do as much as possible in every remote call to DPE.
I have a exception on Thread 10320.
But when I just try to read the StackTrace from the thread I get pure garbage.
I can even reproduce this in WinDbg
0:010> .cxr
Resetting default scope
0:010> k
# Child-SP RetAddr Call Site
00 0000008c`6c7fbe18 00007ffe`5978d23b ntdll!NtGetContextThread+0x14
01 0000008c`6c7fbe20 000001bd`63871bfc ntdll!RtlpLocateActivationContextSection+0x13f
02 0000008c`6c7fbec0 00000000`00000002 0x000001bd`63871bfc
03 0000008c`6c7fbec8 00000000`00000002 0x2
04 0000008c`6c7fbed0 0000bddf`f1f90000 0x2
05 0000008c`6c7fbed8 0000bddf`f1f95675 0x0000bddf`f1f90000
06 0000008c`6c7fbee0 00000000`00000000 0x0000bddf`f1f95675
Current thread is just garbage. But if I switch context to the exception and dump the StackTrace again
0:010> .ecxr
rax=00007ff795801fd8 rbx=0000000000000001 rcx=000001bd27a7ff50
rdx=00007ff7958cad88 rsi=000001be54f6a050 rdi=0000000000000000
rip=00007ff7950116ef rsp=0000008c6c7ff1c8 rbp=0000000000000003
r8=0000000000000000 r9=000000000000000e r10=0000000000000004
r11=0000008c6c7ff1c0 r12=0000000000000001 r13=000001bed219ffc0
r14=0000008c6c7ffa70 r15=0000000000000001
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
Arma3_x64!XX::GetClamp+0xf:
00007ff7`950116ef 48ffa0b0000000 jmp qword ptr [rax+0B0h] ds:00007ff7`95802088={Arma3_x64!XX (00007ff7`9434cfd0)}
0:010> k
*** Stack trace for last set context - .thread/.cxr resets it
# Child-SP RetAddr Call Site
00 0000008c`6c7ff1c8 00007ff7`94fb809d Arma3_x64!XXX::GetClamp+0xf [X]
01 0000008c`6c7ff1d0 00007ff7`94f834b4 Arma3_x64!XXX::SetTextureAndMaterial+0x1fd [X]
02 0000008c`6c7ff2e0 00007ff7`94fa1973 Arma3_x64!XXX::DoPrepareTriangle+0x1444 [X]
03 0000008c`6c7ff390 00007ff7`94a22519 Arma3_x64!XXX+0x1e3 [X]
04 0000008c`6c7ff470 00007ff7`94a75bbd Arma3_x64!XXXL+0x1e9 X]
05 0000008c`6c7ff5d0 00007ff7`94a75887 Arma3_x64!XXX+0x29d [X]
06 0000008c`6c7ff740 00007ff7`94e169d6 Arma3_x64!XXX+0x187 [X]
07 0000008c`6c7ff7f0 00007ff7`94df1048 Arma3_x64!XXX+0x376 [X]
08 0000008c`6c7ff9e0 00007ff7`94f41bde Arma3_x64!XXXk::operator()+0xe8 [X]
09 0000008c`6c7ffa70 00007ff7`94f41fb7 Arma3_x64!XXX+0x12e [X]
0a 0000008c`6c7ffab0 00007ffe`57ab7034 Arma3_x64!InheritFPUSettings+0x57 [X]
0b 0000008c`6c7ffae0 00007ffe`597c2651 kernel32!BaseThreadInitThunk+0x14
0c 0000008c`6c7ffb10 00000000`00000000 ntdll!RtlUserThreadStart+0x21
Everything works perfectly fine.
I just cannot figure out how to do it in SharpDebug, well I know how to do it, but not how to do it with the API limitations.
There doesn't seem to be any API to switch the current context to the SharpDebug.DebugEventInfo.LastEvent
My hacky workaround is
And then do a very hacky
SharpDebug.Engine.Debuggers.DbgEngDll.ExecuteAndCapture(".ecxr");
var Adbg = SharpDebug.Engine.Context.Debugger as SharpDebug.Engine.Debuggers.DbgEngDll;
var Actx = Adbg.GetStackTraceFromContext(SharpDebug.Thread.Current, IntPtr.Zero, 0);
Basically change the context to the exception inside dbgeng, and then get stack from current active context (without setting context to thread again via the ThreadSwitcher)
This way works perfectly fine. But its quite a stupid solution.
Line
Rectangle
Circle
Ellipse
Path
Polygon
Text
Pen
Brush
Color
Font
Let's start with having button to verify initialization script.
It would be great to have "editor extension" for highlighting syntax, errors, etc.
https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html
Padding is present, if necessary, to ensure 4-byte alignment for the descriptor. Such padding is not included in namesz.
Thats done correctly here with NameSize:
But the 4-byte padding to the next note is not considered.
The first descsz bytes in desc hold the note descriptor. If no descriptor is present, descsz contains the value zero. Padding is present, if necessary, to ensure 4-byte alignment for the next note entry. Such padding is not included in descsz.
descsz also needs to be 4 byte padded same as name.
Ghetto fix
SharpDebug/Source/SharpDebug.DwarfSymbolProvider/ElfCoreDump.cs
Lines 115 to 117 in 0a19533
string name = reader.ReadString();
reader.Position = nameEnd;
int descEnd = reader.Position + (int)note.DescSizeWithPadding;
byte[] content = reader.ReadBlock(note.n_descsz);
reader.Position = descEnd;
Will make a pull request someday when I get the time for it
Path for searching scripts in Visual Studio should include all project directories and subdirectories as well as a solution directory.
Currently, CodeGen tests are just verifying that compilation is succeeding. Next step would be to execute some interactive code against generated assembly user types and global variables...
All the Attributes parsed in DwarfSymbolProvider.DwarfCompilationUnit.ReadData are not deduplicated/interned.
For a big binary (in my case with debug info about 900MB) this will cause extreme memory usage.
Within the first 100 compilation units my memory usage rises to 12GB and then it gets stuck there because I ran out of memory.
As a ultra ugly hotfix I added this in DwarfSymbolProvider.ParseCompilationUnits
public class StringInterner
{
// deduplicate strings
// meh https://github.com/dotnet/runtime/issues/21603 https://stackoverflow.com/questions/7760364/how-to-retrieve-actual-item-from-hashsett
ConcurrentDictionary<object, object> stringBank = new ConcurrentDictionary<object, object>();
public object InternObject(object str)
{
if (str == null) return str;
if (stringBank.TryGetValue(str, out var result))
{
return result;
}
stringBank.AddOrUpdate(str, str, (x,y)=> x);
return str;
}
}
private static DwarfCompilationUnit[] ParseCompilationUnits(byte[] debugData, byte[] debugDataDescription, byte[] debugStrings, NormalizeAddressDelegate addressNormalizer)
{
using (DwarfMemoryReader debugDataReader = new DwarfMemoryReader(debugData))
using (DwarfMemoryReader debugDataDescriptionReader = new DwarfMemoryReader(debugDataDescription))
using (DwarfMemoryReader debugStringsReader = new DwarfMemoryReader(debugStrings))
{
List<DwarfCompilationUnit> compilationUnits = new List<DwarfCompilationUnit>();
StringInterner interner = new StringInterner();
List<Task> tasksList = new List<Task>();
while (!debugDataReader.IsEnd)
{
DwarfCompilationUnit compilationUnit = new DwarfCompilationUnit(debugDataReader, debugDataDescriptionReader, debugStringsReader, addressNormalizer, interner);
tasksList.Add(Task.Run(() =>
{
// intern all attributes in seperate threads
foreach (var compilationUnitSymbol in compilationUnit.Symbols)
{
compilationUnitSymbol.Attributes =
compilationUnitSymbol.Attributes
.Select(x => new KeyValuePair<DwarfAttribute, DwarfAttributeValue>(x.Key, interner.InternObject(x.Value) as DwarfAttributeValue))
.ToDictionary(x => x.Key, x => x.Value);
}
}));
compilationUnits.Add(compilationUnit);
}
Task.WaitAll(tasksList.ToArray());
return compilationUnits.ToArray();
}
}
This keeps my memory usage at the 400th compilation unit down at 7.7GB which is atleast usable.
I originally did the interning in DwarfCompilationUnit.data but that took too much time, the data reading is already the performance bottleneck, better not add anything extra to it.
Moving it out into a seperate thread/task works well for me so far.
One could probably intern the whole attribute instead of just the attribute value, not sure if that would be better, I assume it won't.
After loading the extension in WinDBG, and performing the command !CsDebugScript.interactive
, the following error dump is thrown:
0:024> .load csext\CsDebugScript.WinDbg.dll
0:024> !CsDebugScript.interactive
System.TypeInitializationException: The type initializer for 'CsDebugScript.Executor' threw an exception. ---> System.TypeInitializationException: The type initializer for 'CsDebugScript.ScriptCompiler' threw an exception. ---> System.IO.FileNotFoundException: The system cannot find the file specified. (Exception from HRESULT: 0x80070002)
at System.Reflection.RuntimeAssembly.nLoadFile(String path, Evidence evidence)
at System.Reflection.Assembly.LoadFile(String path)
at CsDebugScript.ScriptCompiler.GetDefaultAssemblyReferences() in C:\Users\vujova\Documents\GitHub\WinDbgCs\Source\CsDebugScript.UI\ScriptCompiler.cs:line 62
at CsDebugScript.ScriptCompiler..cctor() in C:\Users\vujova\Documents\GitHub\WinDbgCs\Source\CsDebugScript.UI\ScriptCompiler.cs:line 36
--- End of inner exception stack trace ---
at CsDebugScript.InteractiveExecution..ctor() in C:\Users\vujova\Documents\GitHub\WinDbgCs\Source\CsDebugScript.UI\InteractiveExecution.cs:line 47
at CsDebugScript.Executor..cctor() in C:\Users\vujova\Documents\GitHub\WinDbgCs\Source\CsDebugScript.UI\Executor.cs:line 19
--- End of inner exception stack trace ---
at CsDebugScript.Executor.<>c.b__4_0() in C:\Users\vujova\Documents\GitHub\WinDbgCs\Source\CsDebugScript.UI\Executor.cs:line 58
at CsDebugScript.Engine.Debuggers.DbgEngDll.ExecuteAction(Action action) in C:\Users\vujova\Documents\GitHub\WinDbgCs\Source\CsDebugScript.Engine\Engine\Debuggers\DbgEngDll.cs:line 959
The culprit lines for future reference is the following line:
var assembly = Assembly.LoadFile(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\Microsoft.CSharp.dll");
For the time being, the only option is to copy that file in the same location as the extension. However, that would work only for 64bit machines if someone is using a 32bit machine that solution will not work.
--halsten
When using the DbgEng library to get direct access to the debugging APIs, I expect WaitForEvent to return an exit code. However, it returns void.
See the original documentation on WaitForEvent:
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/dbgeng/nf-dbgeng-idebugcontrol-waitforevent
Return code | Description |
---|---|
S_OK | The method was successful. |
S_FALSE | The time-out expired. |
E_PENDING | An exit interrupt was issued. The target is not available. |
E_UNEXPECTED | Either there is an outstanding request for input, or none of the targets could generate events. |
E_FAIL | The engine is already waiting for an event. |
I want to take some action based on whether or not WaitForEvent timed out, which is possible with the original API. With WinDbgCS, I need to roll my own mechanism to figure out whether we timed out.
Is this project still alive? Hasn't had commits for a few years and the Nuget package is no longer available.
SharpDebug/Source/SharpDebug.DwarfSymbolProvider/DwarfSymbolProviderModule.cs
Lines 2548 to 2550 in 0a19533
read register twice
https://elixir.bootlin.com/linux/v5.14.14/source/arch/arc/kernel/unwind.c#L790
Its supposed to be register and register value
not register and register again
SharpDebug/Source/SharpDebug.DwarfSymbolProvider/DwarfSymbolProviderModule.cs
Lines 2501 to 2509 in 0a19533
https://elixir.bootlin.com/linux/v5.14.14/source/arch/arc/kernel/unwind.c#L742
It doesn't need to be all tests, but some that are supported :)
There should exist wrapper class and interface that will let easy generation of "constants" in generics.
interface ITemplateConstant { T Value { get; } }
class TemplateConstant<T1, T2> where T1 is ITemplateConstant, new() { static T2 Value { get; } }
There should exist a list of all used constants and referenced from all generated template classes.
Example:
static class TemplateConstants
{
class Int20 : ITemplateConstant { int Value => 20; }
}
Fast usage: TemplateConstant<TemplateConstants.Int20, int>.Value (it returns 20)
This way, template user type can have correct CodeType name in metadata instead of current hack.
There should exist initialization script (Init.csx or similar) that should be executed when debugging starts (or when extension is loaded).
This initialization script can define functions, user types, include other scripts, define list of types that should be visualized by custom user code, etc.
Example: int[100][100]
Generated code should be CodeArray and CodeArray should have index operator for multiple dimensions.
Example that one should be cautious about: int[][100];
Reproduce steps
dotnet build
Expected result: build success
Actual result:
C:\Program Files\dotnet\sdk\5.0.101\NuGet.targets(131,5): error : Unable to load the service index for source https://powershell.myget.org/F/powershell-core/api/v3/index.json. [C:\Users\VITALY\source\repos\SharpDebug\SharpDebug.sln]
C:\Program Files\dotnet\sdk\5.0.101\NuGet.targets(131,5): error : Response status code does not indicate success: 404 (Feed does not exist.). [C:\Users\VITALY\source\repos\SharpDebug\SharpDebug.sln]
CommonUserTypes should have pre-calculated structure that knows how to extract needed fields, so that it is not necessary to use getting fields from Variable. This structure should be kept in TypeSelector and populated in VerifyCodeType functions.
Some of the types can use this structure to be physical user type compatible.
When ran isolated, UserTypeAutoCast tests are succeeding. They need to be reliable on AppVeyor too.
Lots has changed in the past years and it is time to upgrade CLR MD to newer bits...
I was looking for a managed Dwarf parser. I saw comments in ElfSharp about your dwarf parser. I took a quick look at the code it seemed pretty clean so I decided to kick the tires. I tried to use the as a standalone ELF Dwarf Symbol parser.
Summary of my findings:
SharpDebug.Engine.Module
constructor is internal
.If you are interested my branch is here https://github.com/sdmaclea/SharpDebug/tree/DwarfSymbolProvider. With those changes and the change to ElfSharp I was able to fully parse the dwarf symbols from libcoreclr.so.dbg
(see ElfSharp issue above for relevant instructions).
At this moment, CodeGen will throw exception for some compile time constants (mostly constexpr, but some are static const) of complex types (like std::chrono).
Are there examples on how to use the drawing interface?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.