Skip to content

Commit 25d64bb

Browse files
committed
Revamp shared libraries aspect states, lighter now
1 parent 8ef914a commit 25d64bb

9 files changed

+134
-45
lines changed

tools/apput/src/Detector.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ public class Detector
2222
typeof (ApplicationAssembly),
2323
typeof (NativeAotSharedLibrary),
2424
typeof (XamarinAppSharedLibrary),
25+
typeof (MonoAotSharedLibrary),
2526
typeof (SharedLibrary),
2627
};
2728

2829
readonly static List<Type> KnownSharedLibraryAspects = new () {
2930
typeof (NativeAotSharedLibrary),
3031
typeof (XamarinAppSharedLibrary),
32+
typeof (MonoAotSharedLibrary),
3133
typeof (SharedLibrary),
3234
};
3335

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System;
2+
using System.IO;
3+
using ELFSharp.ELF;
4+
5+
namespace ApplicationUtility;
6+
7+
class MonoAotSharedLibrary : SharedLibrary
8+
{
9+
const string MonoAotDataSymbol = "mono_aot_file_info";
10+
11+
protected MonoAotSharedLibrary (Stream stream, string libraryName, MonoAotSharedLibraryAspectState state)
12+
: base (stream, libraryName, state)
13+
{}
14+
15+
public new static IAspect LoadAspect (Stream stream, IAspectState? state, string? description)
16+
{
17+
if (String.IsNullOrEmpty (description)) {
18+
throw new ArgumentException ("Must be a shared library name", nameof (description));
19+
}
20+
21+
var libState = EnsureValidAspectState<MonoAotSharedLibraryAspectState> (state);
22+
return new MonoAotSharedLibrary (stream, description, libState);
23+
}
24+
25+
public static new IAspectState ProbeAspect (Stream stream, string? description) => IsMonoAotSharedLibrary (stream, description);
26+
27+
static MonoAotSharedLibraryAspectState IsMonoAotSharedLibrary (Stream stream, string? description)
28+
{
29+
Log.Debug ($"Checking if '{description}' is a Mono AOT shared library");
30+
if (!IsSupportedELFSharedLibrary (stream, description, out IELF? elf) || elf == null) {
31+
return GetErrorState ();
32+
}
33+
34+
if (!AnELF.TryLoad (stream, description ?? String.Empty, out AnELF? anElf) || anElf == null) {
35+
return GetErrorState ();
36+
}
37+
38+
if (!anElf.HasSymbol (MonoAotDataSymbol)) {
39+
Log.Debug ($"Symbol '{MonoAotDataSymbol}' missing, not a Mono AOT shared library");
40+
return GetErrorState ();
41+
}
42+
43+
return new MonoAotSharedLibraryAspectState (true, anElf);
44+
45+
MonoAotSharedLibraryAspectState GetErrorState () => new MonoAotSharedLibraryAspectState (false, null);
46+
}
47+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace ApplicationUtility;
2+
3+
class MonoAotSharedLibraryAspectState : SharedLibraryAspectState
4+
{
5+
public AnELF? LoadedELF { get; }
6+
7+
public MonoAotSharedLibraryAspectState (bool success, AnELF? elf)
8+
: base (success, elf?.AnyELF)
9+
{
10+
LoadedELF = elf;
11+
}
12+
}

tools/apput/src/Native/NativeAotSharedLibrary.cs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ public class NativeAotSharedLibrary : SharedLibrary
1616
(".hydrated", SectionType.NoBits),
1717
};
1818

19-
protected NativeAotSharedLibrary (Stream stream, string libraryName)
20-
: base (stream, libraryName)
19+
protected NativeAotSharedLibrary (Stream stream, string libraryName, IAspectState state)
20+
: base (stream, libraryName, state)
2121
{}
2222

2323
public new static IAspect LoadAspect (Stream stream, IAspectState? state, string? description)
@@ -26,28 +26,27 @@ protected NativeAotSharedLibrary (Stream stream, string libraryName)
2626
throw new ArgumentException ("Must be a shared library name", nameof (description));
2727
}
2828

29-
if (!IsNativeAotSharedLibrary (stream, description)) {
30-
throw new InvalidOperationException ("Stream is not a supported NativeAOT shared library");
31-
}
32-
33-
return new NativeAotSharedLibrary (stream, description);
29+
var libState = EnsureValidAspectState<NativeAotSharedLibraryAspectState> (state);
30+
return new NativeAotSharedLibrary (stream, description, libState);
3431
}
3532

36-
public new static IAspectState ProbeAspect (Stream stream, string? description) => new BasicAspectState (IsNativeAotSharedLibrary (stream, description));
33+
public new static IAspectState ProbeAspect (Stream stream, string? description) => IsNativeAotSharedLibrary (stream, description);
3734

38-
static bool IsNativeAotSharedLibrary (Stream stream, string? description)
35+
static NativeAotSharedLibraryAspectState IsNativeAotSharedLibrary (Stream stream, string? description)
3936
{
4037
if (!IsSupportedELFSharedLibrary (stream, description, out IELF? elf) || elf == null) {
41-
return false;
38+
return GetErrorState ();
4239
}
4340

4441
// Just one match should be enough
4542
foreach (var naotSection in NativeAotSections) {
4643
if (HasSection (elf, description, naotSection.sectionName, naotSection.type)) {
47-
return true;
44+
return new NativeAotSharedLibraryAspectState (true, elf);
4845
}
4946
}
5047

51-
return false;
48+
return GetErrorState ();
49+
50+
NativeAotSharedLibraryAspectState GetErrorState () => new NativeAotSharedLibraryAspectState (false, null);
5251
}
5352
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using ELFSharp.ELF;
2+
3+
namespace ApplicationUtility;
4+
5+
class NativeAotSharedLibraryAspectState : SharedLibraryAspectState
6+
{
7+
public NativeAotSharedLibraryAspectState (bool success, IELF? elf)
8+
: base (success, elf)
9+
{}
10+
}

tools/apput/src/Native/SharedLibrary.cs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,14 @@ public class SharedLibrary : IAspect, IDisposable
5050

5151
protected IELF ELF => elf;
5252

53-
protected SharedLibrary (Stream stream, string libraryName)
53+
protected SharedLibrary (Stream stream, string libraryName, IAspectState state)
5454
{
55+
var libState = EnsureValidAspectState<SharedLibraryAspectState> (state);
56+
5557
this.libraryStream = stream;
5658
this.libraryName = libraryName;
57-
(elf, is64Bit, nativeArch) = LoadELF (stream, libraryName);
59+
elf = libState.ElfImage!;
60+
(is64Bit, nativeArch) = ValidateELF (libState.ElfImage!, libraryName);
5861
(payloadOffset, payloadSize) = FindAndroidPayload (elf);
5962
libraryAlignment = DetectAlignment (elf, is64Bit);
6063
(hasDebugInfo, debugLink) = DetectDebugInfo (elf, libraryName);
@@ -63,20 +66,31 @@ protected SharedLibrary (Stream stream, string libraryName)
6366
soname = GetSoname (elf, is64Bit);
6467
}
6568

69+
protected static T EnsureValidAspectState<T> (IAspectState? state) where T: IAspectState
70+
{
71+
if (!(state is SharedLibraryAspectState libState)) {
72+
throw new InvalidOperationException ("Internal error: invalid aspect state, call ProbeAspect to get one.");
73+
}
74+
75+
if (!libState.Success || libState.ElfImage == null) {
76+
throw new InvalidOperationException ("Internal error: ProbeAspect failed to detect a valid shared library.");
77+
}
78+
79+
return (T)((object)libState);
80+
}
81+
6682
public static IAspect LoadAspect (Stream stream, IAspectState? state, string? description)
6783
{
6884
if (String.IsNullOrEmpty (description)) {
6985
throw new ArgumentException ("Must be a shared library name", nameof (description));
7086
}
7187

72-
if (!IsSupportedELFSharedLibrary (stream, description)) {
73-
throw new InvalidOperationException ("Stream is not a supported ELF shared library");
74-
}
88+
var libState = EnsureValidAspectState<SharedLibraryAspectState> (state);
7589

76-
return new SharedLibrary (stream, description);
90+
return new SharedLibrary (stream, description, libState);
7791
}
7892

79-
public static IAspectState ProbeAspect (Stream stream, string? description) => new BasicAspectState (IsSupportedELFSharedLibrary (stream, description));
93+
public static IAspectState ProbeAspect (Stream stream, string? description) => IsSupportedELFSharedLibrary (stream, description);
8094

8195
/// <summary>
8296
/// If the library has .NET for Android payload section, this
@@ -164,35 +178,26 @@ protected static bool IsSupportedELFSharedLibrary (Stream stream, string? descri
164178
return supported;
165179
}
166180

167-
protected static bool IsSupportedELFSharedLibrary (Stream stream, string? description)
181+
protected static IAspectState IsSupportedELFSharedLibrary (Stream stream, string? description)
168182
{
169183
if (!IsSupportedELFSharedLibrary (stream, description, out IELF? elf) || elf == null) {
170-
return false;
184+
return new SharedLibraryAspectState (false, null);
171185
}
172186

173-
elf.Dispose ();
174-
return true;
187+
return new SharedLibraryAspectState (true, elf);
175188
}
176189

177-
// We assume below that stream corresponds to a valid and supported by us ELF image. This should have been asserted by
178-
// the `LoadAspect` method.
179-
(IELF elf, bool is64bit, NativeArchitecture nativeArch) LoadELF (Stream stream, string? libraryName)
190+
(bool is64bit, NativeArchitecture nativeArch) ValidateELF (IELF elf, string? libraryName)
180191
{
181-
stream.Seek (0, SeekOrigin.Begin);
182-
if (!ELFReader.TryLoad (stream, shouldOwnStream: false, out IELF? elf) || elf == null) {
183-
Log.Debug ($"SharedLibrary: stream ('{libraryName}') failed to load as an ELF image.");
184-
throw new InvalidOperationException ($"Failed to load ELF library '{libraryName}'.");
185-
}
186-
187192
(bool is64, NativeArchitecture arch) = elf.Machine switch {
188193
Machine.ARM => (false, NativeArchitecture.Arm),
189194
Machine.Intel386 => (false, NativeArchitecture.X86),
190195
Machine.AArch64 => (true, NativeArchitecture.Arm64),
191196
Machine.AMD64 => (true, NativeArchitecture.X64),
192-
_ => throw new NotSupportedException ($"Unsupported ELF architecture '{elf.Machine}'")
197+
_ => throw new NotSupportedException ($"Unsupported ELF architecture '{elf.Machine}' for '{libraryName}'")
193198
};
194199

195-
return (elf, is64, arch);
200+
return (is64, arch);
196201
}
197202

198203
(ulong offset, ulong size) FindAndroidPayload (IELF elf)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using ELFSharp.ELF;
2+
3+
namespace ApplicationUtility;
4+
5+
class SharedLibraryAspectState : BasicAspectState
6+
{
7+
public IELF? ElfImage { get; }
8+
9+
public SharedLibraryAspectState (bool success, IELF? elf)
10+
: base (success)
11+
{
12+
ElfImage = elf;
13+
}
14+
}
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
namespace ApplicationUtility;
22

3-
class XamarinAppLibraryAspectState : BasicAspectState
3+
class XamarinAppLibraryAspectState : SharedLibraryAspectState
44
{
5+
public AnELF? LoadedELF { get; }
56
public ulong FormatTag { get; }
67

7-
public XamarinAppLibraryAspectState (bool success, ulong formatTag)
8-
: base (success)
8+
public XamarinAppLibraryAspectState (bool success, ulong formatTag, AnELF? elf)
9+
: base (success, elf?.AnyELF)
910
{
1011
FormatTag = formatTag;
12+
LoadedELF = elf;
1113
}
1214
}

tools/apput/src/Native/XamarinAppSharedLibrary.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class XamarinAppSharedLibrary : SharedLibrary
1313
public ulong FormatTag { get; }
1414

1515
XamarinAppSharedLibrary (Stream stream, string description, XamarinAppLibraryAspectState state)
16-
: base (stream, description)
16+
: base (stream, description, state)
1717
{
1818
FormatTag = state.FormatTag;
1919
}
@@ -24,12 +24,10 @@ class XamarinAppSharedLibrary : SharedLibrary
2424
throw new ArgumentException ("Must be a shared library name", nameof (description));
2525
}
2626

27-
if (!IsSupportedELFSharedLibrary (stream, description)) {
28-
throw new InvalidOperationException ("Stream is not a supported ELF shared library");
29-
}
27+
var libState = EnsureValidAspectState<XamarinAppLibraryAspectState> (state);
3028

3129
// TODO: this needs to be versioned
32-
return new XamarinAppSharedLibrary (stream, description, (XamarinAppLibraryAspectState)state);
30+
return new XamarinAppSharedLibrary (stream, description, libState);
3331
}
3432

3533
public static new IAspectState ProbeAspect (Stream stream, string? description) => IsXamarinAppSharedLibrary (stream, description);
@@ -51,15 +49,15 @@ static XamarinAppLibraryAspectState IsXamarinAppSharedLibrary (Stream stream, st
5149
ulong formatTag = anElf.GetUInt64 (FormatTagSymbol);
5250

5351
// TODO: check for presence of a handful of fields more
54-
return GetState (success: true, formatTag);
52+
return GetState (success: true, formatTag, anElf);
5553

5654
XamarinAppLibraryAspectState LogMissingSymbolAndReturn (string name)
5755
{
5856
Log.Debug ($"{description} is not a Xamarin.Android application shared library, it doesn't have the '{name}' symbol.");
5957
return GetErrorState ();
6058
}
6159

62-
XamarinAppLibraryAspectState GetState (bool success, ulong formatTag) => new XamarinAppLibraryAspectState (success, formatTag);
63-
XamarinAppLibraryAspectState GetErrorState () => GetState (success: false, formatTag: 0);
60+
XamarinAppLibraryAspectState GetState (bool success, ulong formatTag, AnELF? elf) => new XamarinAppLibraryAspectState (success, formatTag, elf);
61+
XamarinAppLibraryAspectState GetErrorState () => GetState (success: false, formatTag: 0, elf: null);
6462
}
6563
}

0 commit comments

Comments
 (0)