2 using System
.Collections
.Generic
;
5 using System
.Text
.RegularExpressions
;
7 using CppSharp
.AST
.Extensions
;
13 * This tool dumps the offsets of structures used in the Mono VM needed
14 * by the AOT compiler for cross-compiling code to target platforms
15 * different than the host the compiler is being invoked on.
17 * It takes two arguments: the path to your clone of the Mono repo and
18 * the path to the root of Android NDK.
20 static class MonoAotOffsetsDumper
22 static string MonoDir
= @"";
24 static List
<string> Abis
= new List
<string> ();
25 static string OutputDir
;
27 static string MonodroidDir
= @"";
28 static string AndroidNdkPath
= @"";
29 static string MaccoreDir
= @"";
30 static string TargetDir
= @"";
32 public enum TargetPlatform
43 Defines
= new List
<string>();
44 Arguments
= new List
<string>();
47 public Target(Target target
)
49 Platform
= target
.Platform
;
50 Triple
= target
.Triple
;
52 Defines
= target
.Defines
;
53 Arguments
= target
.Arguments
;
56 public TargetPlatform Platform
;
59 public List
<string> Defines
;
60 public List
<string> Arguments
;
63 public static List
<Target
> Targets
= new List
<Target
>();
65 public static IEnumerable
<Target
> AndroidTargets
67 get { return Targets.Where ((t) => t.Platform == TargetPlatform.Android); }
70 public static IEnumerable
<Target
> DarwinTargets
74 return Targets
.Where ((t
) => t
.Platform
== TargetPlatform
.iOS
||
75 t
.Platform
== TargetPlatform
.WatchOS
);
79 public static IEnumerable
<Target
> iOSTargets
83 return Targets
.Where ((t
) => t
.Platform
== TargetPlatform
.iOS
);
87 public static void SetupAndroidTargets()
89 Targets
.Add (new Target
{
90 Platform
= TargetPlatform
.Android
,
91 Triple
= "i686-none-linux-android",
92 Defines
= { "TARGET_X86" }
95 Targets
.Add (new Target
{
96 Platform
= TargetPlatform
.Android
,
97 Triple
= "x86_64-none-linux-android",
98 Defines
= { "TARGET_AMD64" }
101 Targets
.Add (new Target
{
102 Platform
= TargetPlatform
.Android
,
103 Triple
= "armv5-none-linux-androideabi",
104 Defines
= { "TARGET_ARM", "ARM_FPU_VFP", "HAVE_ARMV5" }
107 Targets
.Add (new Target
{
108 Platform
= TargetPlatform
.Android
,
109 Triple
= "armv7-none-linux-androideabi",
110 Defines
= { "TARGET_ARM", "ARM_FPU_VFP", "HAVE_ARMV5", "HAVE_ARMV6",
115 Targets
.Add (new Target
{
116 Platform
= TargetPlatform
.Android
,
117 Triple
= "aarch64-v8a-linux-android",
118 Defines
= { "TARGET_ARM64" }
121 /*Targets.Add(new Target {
122 Platform = TargetPlatform.Android,
123 Triple = "mipsel-none-linux-android",
124 Defines = { "TARGET_MIPS", "__mips__" }
127 foreach (var target
in AndroidTargets
)
128 target
.Defines
.AddRange (new string[] { "PLATFORM_ANDROID",
129 "TARGET_ANDROID", "MONO_CROSS_COMPILE", "USE_MONO_CTX"
133 public static void SetupiOSTargets()
135 Targets
.Add(new Target
{
136 Platform
= TargetPlatform
.iOS
,
137 Triple
= "arm-apple-darwin10",
139 Defines
= { "TARGET_ARM", "ARM_FPU_VFP", "HAVE_ARMV5" }
142 Targets
.Add(new Target
{
143 Platform
= TargetPlatform
.iOS
,
144 Triple
= "aarch64-apple-darwin10",
146 Defines
= { "TARGET_ARM64" }
149 foreach (var target
in iOSTargets
) {
150 target
.Defines
.AddRange (new string[] { "PLATFORM_DARWIN",
151 "TARGET_IOS", "TARGET_MACH", "MONO_CROSS_COMPILE", "USE_MONO_CTX",
156 Targets
.Add(new Target
{
157 Platform
= TargetPlatform
.WatchOS
,
158 Triple
= "armv7k-apple-darwin",
159 Build
= "targetwatch",
160 Defines
= { "TARGET_ARM", "ARM_FPU_VFP", "HAVE_ARMV5" }
163 foreach (var target
in DarwinTargets
) {
164 target
.Defines
.AddRange (new string[] { "PLATFORM_DARWIN",
165 "TARGET_IOS", "TARGET_MACH", "MONO_CROSS_COMPILE", "USE_MONO_CTX",
171 static bool GetParentSubDirectoryPath(string parent
, out string subdir
)
173 var directory
= Directory
.GetParent(Directory
.GetCurrentDirectory());
175 while (directory
!= null) {
176 var path
= Path
.Combine(directory
.FullName
, parent
);
178 if (Directory
.Exists (path
)) {
183 directory
= directory
.Parent
;
190 public static void Main(string[] args
)
192 ParseCommandLineArgs(args
);
195 if (!Directory
.Exists (MonodroidDir
) &&
196 GetParentSubDirectoryPath ("monodroid", out monodroidDir
)) {
197 MonodroidDir
= Path
.Combine (monodroidDir
);
200 if (Directory
.Exists (MonodroidDir
))
201 SetupAndroidTargets();
204 if (!Directory
.Exists (MaccoreDir
) &&
205 GetParentSubDirectoryPath ("maccore", out maccoreDir
)) {
206 MaccoreDir
= Path
.Combine (maccoreDir
);
209 if (Directory
.Exists(MaccoreDir
))
212 foreach (var target
in Targets
)
214 if (Abis
.Any() && !Abis
.Any (target
.Triple
.Contains
))
218 Console
.WriteLine("Processing triple: {0}", target
.Triple
);
220 var options
= new DriverOptions();
222 var log
= new TextDiagnosticPrinter();
223 var driver
= new Driver(options
, log
);
225 Setup(driver
, target
);
228 BuildParseOptions(driver
, target
);
229 if (!driver
.ParseCode())
232 Dump(driver
.Context
.ASTContext
, driver
.Context
.TargetInfo
, target
);
236 static void BuildParseOptions(Driver driver
, Target target
)
238 foreach (var header
in driver
.Options
.Headers
)
240 var source
= driver
.Project
.AddFile(header
);
241 source
.Options
= driver
.BuildParserOptions(source
);
243 if (header
.Contains ("mini"))
246 source
.Options
.AddDefines ("HAVE_SGEN_GC");
247 source
.Options
.AddDefines ("HAVE_MOVING_COLLECTOR");
251 static string GetAndroidNdkPath()
253 if (!String
.IsNullOrEmpty (AndroidNdkPath
))
254 return AndroidNdkPath
;
256 // Find the Android NDK's path from Monodroid's config.
257 var configFile
= Path
.Combine(MonodroidDir
, "env.config");
258 if (!File
.Exists(configFile
))
259 throw new Exception("Expected a valid Monodroid environment config file at " + configFile
);
261 var config
= File
.ReadAllText(configFile
);
262 var match
= Regex
.Match(config
, @"ANDROID_NDK_PATH\s*:=\s(.*)");
263 return match
.Groups
[1].Value
.Trim();
266 static void ParseCommandLineArgs(string[] args
)
268 var showHelp
= false;
270 var options
= new Mono
.Options
.OptionSet () {
271 { "abi=", "ABI triple to generate", v => Abis.Add(v) }
,
272 { "o|out=", "output directory", v => OutputDir = v }
,
273 { "maccore=", "include directory", v => MaccoreDir = v }
,
274 { "monodroid=", "top monodroid directory", v => MonodroidDir = v }
,
275 { "android-ndk=", "Path to Android NDK", v => AndroidNdkPath = v }
,
276 { "targetdir=", "Path to the directory containing the mono build", v =>TargetDir = v }
,
277 { "mono=", "include directory", v => MonoDir = v }
,
278 { "h|help", "show this message and exit", v => showHelp = v != null }
,
282 options
.Parse (args
);
284 catch (Mono
.Options
.OptionException e
) {
285 Console
.WriteLine (e
.Message
);
291 // Print usage and exit.
292 Console
.WriteLine("{0} <options>",
293 AppDomain
.CurrentDomain
.FriendlyName
);
294 options
.WriteOptionDescriptions (Console
.Out
);
299 static void Setup(Driver driver
, Target target
)
301 var options
= driver
.Options
;
302 options
.DryRun
= true;
303 options
.LibraryName
= "Mono";
305 var parserOptions
= driver
.ParserOptions
;
306 parserOptions
.Verbose
= false;
307 parserOptions
.MicrosoftMode
= false;
308 parserOptions
.AddArguments("-xc");
309 parserOptions
.AddArguments("-std=gnu99");
310 parserOptions
.AddDefines("CPPSHARP");
312 foreach (var define
in target
.Defines
)
313 parserOptions
.AddDefines(define
);
315 SetupToolchainPaths(driver
, target
);
317 SetupMono(driver
, target
);
320 static void SetupMono(Driver driver
, Target target
)
323 switch (target
.Platform
) {
324 case TargetPlatform
.Android
:
325 if (TargetDir
== "") {
326 Console
.Error
.WriteLine ("The --targetdir= option is required when targeting android.");
327 Environment
.Exit (1);
330 Console
.Error
.WriteLine ("The --mono= option is required when targeting android.");
331 Environment
.Exit (1);
333 if (Abis
.Count
!= 1) {
334 Console
.Error
.WriteLine ("Exactly one --abi= argument is required when targeting android.");
335 Environment
.Exit (1);
337 targetBuild
= TargetDir
;
339 case TargetPlatform
.WatchOS
:
340 case TargetPlatform
.iOS
: {
341 string targetPath
= Path
.Combine (MaccoreDir
, "builds");
342 if (!Directory
.Exists (MonoDir
))
343 MonoDir
= Path
.GetFullPath (Path
.Combine (targetPath
, "../../mono"));
344 targetBuild
= Path
.Combine(targetPath
, target
.Build
);
348 throw new ArgumentOutOfRangeException ();
351 if (!Directory
.Exists(targetBuild
))
352 throw new Exception(string.Format("Could not find the target build directory: {0}", targetBuild
));
354 var includeDirs
= new[]
357 Path
.Combine(targetBuild
, "eglib", "src"),
359 Path
.Combine(MonoDir
, "mono"),
360 Path
.Combine(MonoDir
, "mono", "mini"),
361 Path
.Combine(MonoDir
, "eglib", "src")
364 foreach (var inc
in includeDirs
)
365 driver
.ParserOptions
.AddIncludeDirs(inc
);
367 var filesToParse
= new[]
369 Path
.Combine(MonoDir
, "mono", "metadata", "metadata-cross-helpers.c"),
370 Path
.Combine(MonoDir
, "mono", "mini", "mini-cross-helpers.c"),
373 foreach (var file
in filesToParse
)
374 driver
.Options
.Headers
.Add(file
);
377 static void SetupMSVC(Driver driver
, string triple
)
379 var parserOptions
= driver
.ParserOptions
;
381 parserOptions
.Abi
= Parser
.AST
.CppAbi
.Microsoft
;
382 parserOptions
.MicrosoftMode
= true;
384 var systemIncludeDirs
= new[]
386 @"C:\Program Files (x86)\Windows Kits\8.1\Include\um",
387 @"C:\Program Files (x86)\Windows Kits\8.1\Include\shared"
390 foreach (var inc
in systemIncludeDirs
)
391 parserOptions
.AddSystemIncludeDirs(inc
);
393 parserOptions
.AddDefines("HOST_WIN32");
396 static void SetupToolchainPaths(Driver driver
, Target target
)
398 switch (target
.Platform
) {
399 case TargetPlatform
.Android
:
400 SetupAndroidNDK(driver
, target
);
402 case TargetPlatform
.iOS
:
403 case TargetPlatform
.WatchOS
:
404 SetupXcode(driver
, target
);
407 throw new ArgumentOutOfRangeException ();
411 static string GetArchFromTriple(string triple
)
413 if (triple
.Contains("mips"))
416 if (triple
.Contains("arm64") || triple
.Contains("aarch64"))
419 if (triple
.Contains("arm"))
422 if (triple
.Contains("i686"))
425 if (triple
.Contains("x86_64"))
428 throw new Exception("Unknown architecture from triple: " + triple
);
431 static string GetXcodeToolchainPath()
433 var toolchains
= Directory
.EnumerateDirectories("/Applications", "Xcode*")
437 var toolchainPath
= toolchains
.LastOrDefault();
438 if (toolchainPath
== null)
439 throw new Exception("Could not find a valid Xcode SDK");
441 return toolchainPath
;
444 static string GetXcodeBuiltinIncludesFolder()
446 var toolchainPath
= GetXcodeToolchainPath();
448 var toolchains
= Directory
.EnumerateDirectories(Path
.Combine(toolchainPath
,
449 "Contents/Developer/Toolchains")).ToList();
452 toolchainPath
= toolchains
.LastOrDefault();
453 if (toolchainPath
== null)
454 throw new Exception("Could not find a valid Xcode toolchain");
456 var includePaths
= Directory
.EnumerateDirectories(Path
.Combine(toolchainPath
,
457 "usr/lib/clang")).ToList();
458 var includePath
= includePaths
.LastOrDefault();
460 if (includePath
== null)
461 throw new Exception("Could not find a valid Clang include folder");
463 return Path
.Combine(includePath
, "include");
466 static string GetXcodeiOSIncludesFolder()
468 var toolchainPath
= GetXcodeToolchainPath();
470 var sdkPaths
= Directory
.EnumerateDirectories(Path
.Combine(toolchainPath
,
471 "Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs")).ToList();
472 var sdkPath
= sdkPaths
.LastOrDefault();
475 throw new Exception("Could not find a valid iPhone SDK");
477 return Path
.Combine(sdkPath
, "usr/include");
480 static string GetXcodeWatchOSIncludesFolder()
482 var toolchainPath
= GetXcodeToolchainPath();
484 var sdkPaths
= Directory
.EnumerateDirectories(Path
.Combine(toolchainPath
,
485 "Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs")).ToList();
486 var sdkPath
= sdkPaths
.LastOrDefault();
489 throw new Exception("Could not find a valid WatchOS SDK");
491 return Path
.Combine(sdkPath
, "usr/include");
494 static void SetupXcode(Driver driver
, Target target
)
496 var parserOptions
= driver
.ParserOptions
;
498 var builtinsPath
= GetXcodeBuiltinIncludesFolder();
501 switch (target
.Platform
) {
502 case TargetPlatform
.iOS
:
503 includePath
= GetXcodeiOSIncludesFolder();
505 case TargetPlatform
.WatchOS
:
506 includePath
= GetXcodeWatchOSIncludesFolder();
509 throw new ArgumentOutOfRangeException ();
512 parserOptions
.AddSystemIncludeDirs(builtinsPath
);
513 parserOptions
.AddSystemIncludeDirs(includePath
);
515 parserOptions
.NoBuiltinIncludes
= true;
516 parserOptions
.NoStandardIncludes
= true;
517 parserOptions
.TargetTriple
= target
.Triple
;
520 static string GetAndroidHostToolchainPath()
522 var androidNdkPath
= GetAndroidNdkPath ();
523 var toolchains
= Directory
.EnumerateDirectories(
524 Path
.Combine(androidNdkPath
, "toolchains"), "llvm*").ToList();
527 var toolchainPath
= toolchains
.LastOrDefault();
528 if (toolchainPath
== null)
529 throw new Exception("Could not find a valid NDK host toolchain");
531 toolchains
= Directory
.EnumerateDirectories(Path
.Combine(toolchainPath
,
532 "prebuilt")).ToList();
535 toolchainPath
= toolchains
.LastOrDefault();
536 if (toolchainPath
== null)
537 throw new Exception("Could not find a valid NDK host toolchain");
539 return toolchainPath
;
542 static string GetAndroidBuiltinIncludesFolder()
544 var toolchainPath
= GetAndroidHostToolchainPath();
546 string clangToolchainPath
= Path
.Combine(toolchainPath
, "lib64", "clang");
547 if (!Directory
.Exists (clangToolchainPath
))
548 clangToolchainPath
= Path
.Combine(toolchainPath
, "lib", "clang");
550 string includePath
= null;
551 if (Directory
.Exists (clangToolchainPath
)) {
552 var includePaths
= Directory
.EnumerateDirectories(clangToolchainPath
).ToList();
553 includePath
= includePaths
.LastOrDefault();
555 if (includePath
== null)
556 throw new Exception("Could not find a valid Clang include folder");
558 return Path
.Combine(includePath
, "include");
561 static void SetupAndroidNDK(Driver driver
, Target target
)
563 var options
= driver
.Options
;
564 var parserOptions
= driver
.ParserOptions
;
566 var builtinsPath
= GetAndroidBuiltinIncludesFolder();
567 parserOptions
.AddSystemIncludeDirs(builtinsPath
);
569 var androidNdkRoot
= GetAndroidNdkPath ();
570 const int androidNdkApiLevel
= 21;
572 var toolchainPath
= Path
.Combine(androidNdkRoot
, "platforms",
573 "android-" + androidNdkApiLevel
, "arch-" + GetArchFromTriple(target
.Triple
),
575 parserOptions
.AddSystemIncludeDirs(toolchainPath
);
577 parserOptions
.NoBuiltinIncludes
= true;
578 parserOptions
.NoStandardIncludes
= true;
579 parserOptions
.TargetTriple
= target
.Triple
;
582 static uint GetTypeAlign(ParserTargetInfo target
, ParserIntType type
)
586 case ParserIntType
.SignedChar
:
587 case ParserIntType
.UnsignedChar
:
588 return target
.CharAlign
;
589 case ParserIntType
.SignedShort
:
590 case ParserIntType
.UnsignedShort
:
591 return target
.ShortAlign
;
592 case ParserIntType
.SignedInt
:
593 case ParserIntType
.UnsignedInt
:
594 return target
.IntAlign
;
595 case ParserIntType
.SignedLong
:
596 case ParserIntType
.UnsignedLong
:
597 return target
.LongAlign
;
598 case ParserIntType
.SignedLongLong
:
599 case ParserIntType
.UnsignedLongLong
:
600 return target
.LongLongAlign
;
602 throw new Exception("Type has no alignment");
606 static uint GetTypeSize(ParserTargetInfo target
, ParserIntType type
)
610 case ParserIntType
.SignedChar
:
611 case ParserIntType
.UnsignedChar
:
612 return target
.CharWidth
;
613 case ParserIntType
.SignedShort
:
614 case ParserIntType
.UnsignedShort
:
615 return target
.ShortWidth
;
616 case ParserIntType
.SignedInt
:
617 case ParserIntType
.UnsignedInt
:
618 return target
.IntWidth
;
619 case ParserIntType
.SignedLong
:
620 case ParserIntType
.UnsignedLong
:
621 return target
.LongWidth
;
622 case ParserIntType
.SignedLongLong
:
623 case ParserIntType
.UnsignedLongLong
:
624 return target
.LongLongWidth
;
626 throw new Exception("Type has no size");
630 static string GetTargetPlatformDefine(TargetPlatform target
)
633 case TargetPlatform
.Android
:
634 return "TARGET_ANDROID";
635 case TargetPlatform
.iOS
:
637 case TargetPlatform
.WatchOS
:
638 return "TARGET_WATCHOS";
640 throw new ArgumentOutOfRangeException ();
644 static void Dump(ASTContext ctx
, ParserTargetInfo targetInfo
, Target target
)
646 var targetFile
= target
.Triple
;
648 if (!string.IsNullOrEmpty (OutputDir
))
649 targetFile
= Path
.Combine (OutputDir
, targetFile
);
653 using (var writer
= new StreamWriter(targetFile
))
654 //using (var writer = Console.Out)
656 writer
.WriteLine("#ifndef USED_CROSS_COMPILER_OFFSETS");
657 writer
.WriteLine("#ifdef {0}", target
.Defines
[0]);
658 writer
.WriteLine ("#ifdef {0}", GetTargetPlatformDefine (target
.Platform
));
659 writer
.WriteLine("#ifndef HAVE_BOEHM_GC");
660 writer
.WriteLine("#define HAS_CROSS_COMPILER_OFFSETS");
661 writer
.WriteLine("#if defined (USE_CROSS_COMPILE_OFFSETS) || defined (MONO_CROSS_COMPILE)");
662 writer
.WriteLine("#if !defined (DISABLE_METADATA_OFFSETS)");
663 writer
.WriteLine("#define USED_CROSS_COMPILER_OFFSETS");
665 DumpAligns(writer
, targetInfo
);
666 DumpSizes(writer
, targetInfo
);
667 DumpMetadataOffsets(writer
, ctx
, target
);
669 writer
.WriteLine("#endif //disable metadata check");
671 DumpJITOffsets(writer
, ctx
);
673 writer
.WriteLine("#endif //cross compiler checks");
674 writer
.WriteLine("#endif //gc check");
675 writer
.WriteLine("#endif //os check");
676 writer
.WriteLine("#endif //arch check");
677 writer
.WriteLine("#endif //USED_CROSS_COMPILER_OFFSETS check");
680 Console
.WriteLine("Generated offsets file: {0}", targetFile
);
683 static void DumpAligns(TextWriter writer
, ParserTargetInfo target
)
687 new { Name = "gint8", Align = target.CharAlign}
,
688 new { Name = "gint16", Align = target.ShortAlign}
,
689 new { Name = "gint32", Align = target.IntAlign}
,
690 new { Name = "gint64", Align = GetTypeAlign(target, target.Int64Type)}
,
691 new { Name = "float", Align = target.FloatAlign}
,
692 new { Name = "double", Align = target.DoubleAlign}
,
693 new { Name = "gpointer", Align = GetTypeAlign(target, target.IntPtrType)}
,
696 // Write the alignment info for the basic types.
697 foreach (var align
in aligns
)
698 writer
.WriteLine("DECL_ALIGN2({0},{1})", align
.Name
, align
.Align
/ 8);
701 static void DumpSizes(TextWriter writer
, ParserTargetInfo target
)
705 new { Name = "gint8", Size = target.CharWidth}
,
706 new { Name = "gint16", Size = target.ShortWidth}
,
707 new { Name = "gint32", Size = target.IntWidth}
,
708 new { Name = "gint64", Size = GetTypeSize(target, target.Int64Type)}
,
709 new { Name = "float", Size = target.FloatWidth}
,
710 new { Name = "double", Size = target.DoubleWidth}
,
711 new { Name = "gpointer", Size = GetTypeSize(target, target.IntPtrType)}
,
714 // Write the size info for the basic types.
715 foreach (var size
in sizes
)
716 writer
.WriteLine("DECL_SIZE2({0},{1})", size
.Name
, size
.Size
/ 8);
719 static Class
GetClassFromTypedef(ITypedDecl typedef
)
721 var type
= typedef
.Type
.Desugar() as TagType
;
725 var @class = type
.Declaration
as Class
;
727 return @class.IsIncomplete
?
728 (@class.CompleteDeclaration
as Class
) : @class;
731 static void DumpClasses(TextWriter writer
, ASTContext ctx
, IEnumerable
<string> types
,
732 bool optional
= false)
734 foreach (var @struct in types
)
736 var @class = ctx
.FindCompleteClass(@struct);
738 @class = ctx
.FindCompleteClass("_" + @struct);
742 var typedef
= ctx
.FindTypedef(@struct).FirstOrDefault(
743 decl
=> !decl
.IsIncomplete
);
746 @class = GetClassFromTypedef(typedef
);
749 if (@class == null && optional
)
753 throw new Exception("Expected to find struct definition for " + @struct);
755 DumpStruct(writer
, @class);
759 static void DumpMetadataOffsets(TextWriter writer
, ASTContext ctx
, Target target
)
761 var types
= new List
<string>
764 "MonoObjectHandlePayload",
768 "MonoInternalThread",
769 "MonoMulticastDelegate",
770 "MonoTransparentProxy",
777 "MonoComInteropProxy",
783 "SgenClientThreadInfo"
786 DumpClasses(writer
, ctx
, types
);
789 static void DumpJITOffsets(TextWriter writer
, ASTContext ctx
)
791 writer
.WriteLine("#ifndef DISABLE_JIT_OFFSETS");
792 writer
.WriteLine("#define USED_CROSS_COMPILER_OFFSETS");
797 "MonoMethodRuntimeGenericContext",
799 "MonoGSharedVtMethodRuntimeInfo",
802 "MonoDelegateTrampInfo",
805 DumpClasses(writer
, ctx
, types
);
807 var optionalTypes
= new[]
815 DumpClasses(writer
, ctx
, optionalTypes
, optional
: true);
817 writer
.WriteLine("#endif //disable jit check");
820 static void DumpStruct(TextWriter writer
, Class
@class)
822 var name
= @class.Name
;
823 if (name
.StartsWith ("_", StringComparison
.Ordinal
))
824 name
= name
.Substring (1);
826 foreach (var field
in @class.Fields
)
828 if (field
.IsBitField
) continue;
830 if (name
== "SgenThreadInfo" && field
.Name
== "regs")
833 var layout
= @class.Layout
.Fields
.First(f
=> f
.FieldPtr
== field
.OriginalPtr
);
835 writer
.WriteLine("DECL_OFFSET2({0},{1},{2})", name
, field
.Name
,