Skip to content

Commit f4d99ab

Browse files
adamsitnikjanvorli
andauthored
arm64 disassembler (#2127)
* make ClrMdV2Disassembler abstract, introduce Arm and Intel disassemblers * Capstone PoC * Implement TryGetReferencedAddress for relative branches (#2107) * Resolve indirect addresses in disassembly (#2118) Co-authored-by: Jan Vorlicek <[email protected]> * Initial version of the Arm64 instruction formatter (#2119) * Added other arm64 constant form extraction plus other changes (#2123) Co-authored-by: Jan Vorlicek <[email protected]> Co-authored-by: Jan Vorlicek <[email protected]>
1 parent a78c2e6 commit f4d99ab

25 files changed

+780
-230
lines changed

samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@
2424
<ProjectReference Include="..\..\src\BenchmarkDotNet\BenchmarkDotNet.csproj" />
2525
<ProjectReference Include="..\..\src\BenchmarkDotNet.Diagnostics.Windows\BenchmarkDotNet.Diagnostics.Windows.csproj" />
2626
</ItemGroup>
27-
</Project>
27+
</Project>

samples/BenchmarkDotNet.Samples/IntroDisassembly.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using BenchmarkDotNet.Attributes;
2+
using BenchmarkDotNet.Diagnosers;
23
using System.Linq;
34

45
namespace BenchmarkDotNet.Samples
56
{
6-
[DisassemblyDiagnoser]
7+
[DisassemblyDiagnoser(printInstructionAddresses: true, syntax: DisassemblySyntax.Masm)]
78
public class IntroDisassembly
89
{
910
private int[] field = Enumerable.Range(0, 100).ToArray();

src/BenchmarkDotNet.Disassembler.x64/BenchmarkDotNet.Disassembler.x64.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
99
<PlatformTarget>x64</PlatformTarget>
1010
<SuppressNETCoreSdkPreviewMessage>True</SuppressNETCoreSdkPreviewMessage>
11+
<DefineConstants>$(DefineConstants);CLRMDV1</DefineConstants>
1112
</PropertyGroup>
1213
<PropertyGroup>
1314
<OutputPath>..\BenchmarkDotNet\Disassemblers</OutputPath>

src/BenchmarkDotNet.Disassembler.x64/ClrMdV1Disassembler.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ internal static DisassemblyResult AttachAndDisassemble(Settings settings)
2525

2626
ConfigureSymbols(dataTarget);
2727

28-
var state = new State(runtime);
28+
var state = new State(runtime, settings.TargetFrameworkMoniker);
2929

3030
if (settings.Filters.Length > 0)
3131
{
@@ -169,21 +169,23 @@ private static IEnumerable<Asm> Decode(ulong startAddress, uint size, State stat
169169
{
170170
decoder.Decode(out var instruction);
171171

172-
TryTranslateAddressToName(instruction, state, depth, currentMethod);
172+
TryTranslateAddressToName(instruction, state, depth, currentMethod, out ulong referencedAddress);
173173

174174
yield return new Asm
175175
{
176176
InstructionPointer = instruction.IP,
177-
Instruction = instruction
177+
InstructionLength = instruction.Length,
178+
IntelInstruction = instruction,
179+
ReferencedAddress = (referencedAddress > ushort.MaxValue) ? referencedAddress : null,
178180
};
179181
}
180182
}
181183

182-
private static void TryTranslateAddressToName(Instruction instruction, State state, int depth, ClrMethod currentMethod)
184+
private static void TryTranslateAddressToName(Instruction instruction, State state, int depth, ClrMethod currentMethod, out ulong address)
183185
{
184186
var runtime = state.Runtime;
185187

186-
if (!TryGetReferencedAddress(instruction, (uint)runtime.PointerSize, out ulong address))
188+
if (!TryGetReferencedAddress(instruction, (uint)runtime.PointerSize, out address))
187189
return;
188190

189191
if (state.AddressToNameMapping.ContainsKey(address))

src/BenchmarkDotNet.Disassembler.x64/DataContracts.cs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@ public class Sharp : SourceCode
2424

2525
public class Asm : SourceCode
2626
{
27-
public Instruction Instruction { get; set; }
27+
public int InstructionLength { get; set; }
28+
public ulong? ReferencedAddress { get; set; }
29+
public bool IsReferencedAddressIndirect { get; set; }
30+
31+
public Instruction? IntelInstruction { get; set; }
32+
#if !CLRMDV1
33+
public Gee.External.Capstone.Arm64.Arm64Instruction Arm64Instruction { get; set; }
34+
#endif
2835
}
2936

3037
public class MonoCode : SourceCode
@@ -101,14 +108,16 @@ public static class DisassemblerConstants
101108

102109
internal class Settings
103110
{
104-
internal Settings(int processId, string typeName, string methodName, bool printSource, int maxDepth, string resultsPath, string[] filters)
111+
internal Settings(int processId, string typeName, string methodName, bool printSource, int maxDepth, string resultsPath, string syntax, string tfm, string[] filters)
105112
{
106113
ProcessId = processId;
107114
TypeName = typeName;
108115
MethodName = methodName;
109116
PrintSource = printSource;
110117
MaxDepth = methodName == DisassemblerConstants.DisassemblerEntryMethodName && maxDepth != int.MaxValue ? maxDepth + 1 : maxDepth;
111118
ResultsPath = resultsPath;
119+
Syntax = syntax;
120+
TargetFrameworkMoniker = tfm;
112121
Filters = filters;
113122
}
114123

@@ -118,6 +127,8 @@ internal Settings(int processId, string typeName, string methodName, bool printS
118127
internal bool PrintSource { get; }
119128
internal int MaxDepth { get; }
120129
internal string[] Filters;
130+
internal string Syntax { get; }
131+
internal string TargetFrameworkMoniker { get; }
121132
internal string ResultsPath { get; }
122133

123134
internal static Settings FromArgs(string[] args)
@@ -128,24 +139,54 @@ internal static Settings FromArgs(string[] args)
128139
printSource: bool.Parse(args[3]),
129140
maxDepth: int.Parse(args[4]),
130141
resultsPath: args[5],
131-
filters: args.Skip(6).ToArray()
142+
syntax: args[6],
143+
tfm: args[7],
144+
filters: args.Skip(8).ToArray()
132145
);
133146
}
134147

135148
internal class State
136149
{
137-
internal State(ClrRuntime runtime)
150+
internal State(ClrRuntime runtime, string targetFrameworkMoniker)
138151
{
139152
Runtime = runtime;
140153
Todo = new Queue<MethodInfo>();
141154
HandledMethods = new HashSet<ClrMethod>(new ClrMethodComparer());
142155
AddressToNameMapping = new Dictionary<ulong, string>();
156+
RuntimeVersion = ParseVersion(targetFrameworkMoniker);
143157
}
144158

145159
internal ClrRuntime Runtime { get; }
160+
internal string TargetFrameworkMoniker { get; }
146161
internal Queue<MethodInfo> Todo { get; }
147162
internal HashSet<ClrMethod> HandledMethods { get; }
148163
internal Dictionary<ulong, string> AddressToNameMapping { get; }
164+
internal Version RuntimeVersion { get; }
165+
166+
internal static Version ParseVersion(string targetFrameworkMoniker)
167+
{
168+
int firstDigit = -1, lastDigit = -1;
169+
for (int i = 0; i < targetFrameworkMoniker.Length; i++)
170+
{
171+
if (char.IsDigit(targetFrameworkMoniker[i]))
172+
{
173+
if (firstDigit == -1)
174+
firstDigit = i;
175+
176+
lastDigit = i;
177+
}
178+
else if (targetFrameworkMoniker[i] == '-')
179+
{
180+
break; // it can be platform specific like net7.0-windows8
181+
}
182+
}
183+
184+
string versionToParse = targetFrameworkMoniker.Substring(firstDigit, lastDigit - firstDigit + 1);
185+
if (!versionToParse.Contains(".")) // Full .NET Framework (net48 etc)
186+
versionToParse = string.Join(".", versionToParse.ToCharArray());
187+
188+
return Version.Parse(versionToParse);
189+
}
149190

150191
private sealed class ClrMethodComparer : IEqualityComparer<ClrMethod>
151192
{

src/BenchmarkDotNet.Disassembler.x86/BenchmarkDotNet.Disassembler.x86.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<RuntimeIdentifier>win7-x86</RuntimeIdentifier>
99
<PlatformTarget>x86</PlatformTarget>
1010
<SuppressNETCoreSdkPreviewMessage>True</SuppressNETCoreSdkPreviewMessage>
11+
<DefineConstants>$(DefineConstants);CLRMDV1</DefineConstants>
1112
</PropertyGroup>
1213
<PropertyGroup>
1314
<OutputPath>..\BenchmarkDotNet\Disassemblers</OutputPath>

src/BenchmarkDotNet/Attributes/DisassemblyDiagnoserAttribute.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace BenchmarkDotNet.Attributes
88
public class DisassemblyDiagnoserAttribute : Attribute, IConfigSource
99
{
1010
/// <param name="maxDepth">Includes called methods to given level. 1 by default, indexed from 1. To print just the benchmark set it to 0.</param>
11+
/// <param name="syntax">The disassembly syntax. MASM is the default.</param>
1112
/// <param name="printSource">C#|F#|VB source code will be printed. False by default.</param>
1213
/// <param name="printInstructionAddresses">Print instruction addresses. False by default</param>
1314
/// <param name="exportGithubMarkdown">Exports to GitHub markdown. True by default.</param>
@@ -17,6 +18,7 @@ public class DisassemblyDiagnoserAttribute : Attribute, IConfigSource
1718
/// <param name="filters">Glob patterns applied to full method signatures by the the disassembler.</param>
1819
public DisassemblyDiagnoserAttribute(
1920
int maxDepth = 1,
21+
DisassemblySyntax syntax = DisassemblySyntax.Masm,
2022
bool printSource = false,
2123
bool printInstructionAddresses = false,
2224
bool exportGithubMarkdown = true,
@@ -29,6 +31,7 @@ public DisassemblyDiagnoserAttribute(
2931
new DisassemblyDiagnoser(
3032
new DisassemblyDiagnoserConfig(
3133
maxDepth: maxDepth,
34+
syntax: syntax,
3235
filters: filters,
3336
printSource: printSource,
3437
printInstructionAddresses: printInstructionAddresses,

src/BenchmarkDotNet/BenchmarkDotNet.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<AssemblyTitle>BenchmarkDotNet</AssemblyTitle>
55
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
66
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
7-
<NoWarn>$(NoWarn);1701;1702;1705;1591;3005;NU1702;CS3001;CS3003</NoWarn>
7+
<NoWarn>$(NoWarn);1701;1702;1705;1591;3005;NU1702;CS3001;CS3003;CS8002</NoWarn>
88
<AssemblyName>BenchmarkDotNet</AssemblyName>
99
<PackageId>BenchmarkDotNet</PackageId>
1010
<RootNamespace>BenchmarkDotNet</RootNamespace>
@@ -17,6 +17,7 @@
1717
</ItemGroup>
1818
<ItemGroup>
1919
<PackageReference Include="CommandLineParser" Version="2.4.3" />
20+
<PackageReference Include="Gee.External.Capstone" Version="2.2.0" />
2021
<PackageReference Include="Iced" Version="1.17.0" />
2122
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.2.332302" />
2223
<PackageReference Include="Perfolizer" Version="0.2.1" />

0 commit comments

Comments
 (0)