Skip to content

Commit 35939d6

Browse files
committed
Teach assembly store explorer about embedded stores
1 parent a9e0c18 commit 35939d6

File tree

6 files changed

+155
-54
lines changed

6 files changed

+155
-54
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System;
2+
3+
using ELFSharp.ELF;
4+
using ELFSharp.ELF.Sections;
5+
6+
namespace Xamarin.Android.Tasks;
7+
8+
static partial class ELFHelper
9+
{
10+
public static ISymbolTable? GetSymbolTable (IELF elf, string sectionName)
11+
{
12+
ISection? section = GetSection (elf, sectionName);
13+
if (section == null) {
14+
return null;
15+
}
16+
17+
var symtab = section as ISymbolTable;
18+
if (symtab == null) {
19+
return null;
20+
}
21+
22+
return symtab;
23+
}
24+
25+
public static ISection? GetSection (IELF elf, string sectionName)
26+
{
27+
if (!elf.TryGetSection (sectionName, out ISection section)) {
28+
return null;
29+
}
30+
31+
return section;
32+
}
33+
34+
public static SymbolEntry<T>? FindSymbol<T> (ISymbolTable? symbolTable, string symbolName) where T: struct
35+
{
36+
if (symbolTable == null) {
37+
return null;
38+
}
39+
40+
ISymbolEntry? symbol = null;
41+
foreach (ISymbolEntry entry in symbolTable.Entries) {
42+
if (String.Compare (entry.Name, symbolName, StringComparison.Ordinal) != 0) {
43+
continue;
44+
}
45+
46+
symbol = entry;
47+
break;
48+
}
49+
50+
if (symbol == null) {
51+
return null;
52+
}
53+
54+
Type t = typeof(T);
55+
if (t == typeof(ulong) || t == typeof(uint)) {
56+
return (SymbolEntry<T>)symbol;
57+
}
58+
59+
throw new InvalidOperationException ($"Only `ulong` and `uint` types are accepted");
60+
}
61+
}

src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.cs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
namespace Xamarin.Android.Tasks
1818
{
19-
static class ELFHelper
19+
static partial class ELFHelper
2020
{
2121
public static void AssertValidLibraryAlignment (TaskLoggingHelper log, int alignmentInPages, string path, ITaskItem? item)
2222
{
@@ -218,29 +218,5 @@ bool IsNonEmptyCodeSymbol<T> (SymbolEntry<T>? symbolEntry) where T : struct
218218
return size != 0 && symbolEntry.PointedSection.Type == ELFSectionType.ProgBits;
219219
}
220220
}
221-
222-
static ISymbolTable? GetSymbolTable (IELF elf, string sectionName)
223-
{
224-
ISection? section = GetSection (elf, sectionName);
225-
if (section == null) {
226-
return null;
227-
}
228-
229-
var symtab = section as ISymbolTable;
230-
if (symtab == null) {
231-
return null;
232-
}
233-
234-
return symtab;
235-
}
236-
237-
static ISection? GetSection (IELF elf, string sectionName)
238-
{
239-
if (!elf.TryGetSection (sectionName, out ISection section)) {
240-
return null;
241-
}
242-
243-
return section;
244-
}
245221
}
246222
}

tools/assembly-store-reader-mk2/AssemblyStore/ELFPayloadError.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ enum ELFPayloadError
88
NotSharedLibrary,
99
NotLittleEndian,
1010
NoPayloadSection,
11+
NoEmbeddedStore,
1112
}

tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ public StoreReader_V2 (Stream store, string path)
8686

8787
protected override ulong GetStoreStartDataOffset () => elfOffset;
8888

89+
string PayloadErrorToString (ELFPayloadError error)
90+
{
91+
return error switch {
92+
ELFPayloadError.NotELF => $"Store '{StorePath}' is not a valid ELF binary",
93+
ELFPayloadError.LoadFailed => $"Store '{StorePath}' could not be loaded",
94+
ELFPayloadError.NotSharedLibrary => $"Store '{StorePath}' is not a shared ELF library",
95+
ELFPayloadError.NotLittleEndian => $"Store '{StorePath}' is not a little-endian ELF image",
96+
ELFPayloadError.NoPayloadSection => $"Store '{StorePath}' does not contain the 'payload' section",
97+
ELFPayloadError.NoEmbeddedStore => $"Store '{StorePath}' does not contain embedded data blob",
98+
_ => $"Unknown ELF payload section error for store '{StorePath}': {error}"
99+
};
100+
}
101+
89102
protected override bool IsSupported ()
90103
{
91104
StoreStream.Seek (0, SeekOrigin.Begin);
@@ -94,22 +107,19 @@ protected override bool IsSupported ()
94107
uint magic = reader.ReadUInt32 ();
95108
if (magic == Utils.ELF_MAGIC) {
96109
ELFPayloadError error;
97-
(elfOffset, _, error) = Utils.FindELFPayloadSectionOffsetAndSize (StoreStream);
98-
110+
(elfOffset, _, error) = Utils.FindEmbeddedStoreOffsetAndSize (StoreStream);
99111
if (error != ELFPayloadError.None) {
100-
string message = error switch {
101-
ELFPayloadError.NotELF => $"Store '{StorePath}' is not a valid ELF binary",
102-
ELFPayloadError.LoadFailed => $"Store '{StorePath}' could not be loaded",
103-
ELFPayloadError.NotSharedLibrary => $"Store '{StorePath}' is not a shared ELF library",
104-
ELFPayloadError.NotLittleEndian => $"Store '{StorePath}' is not a little-endian ELF image",
105-
ELFPayloadError.NoPayloadSection => $"Store '{StorePath}' does not contain the 'payload' section",
106-
_ => $"Unknown ELF payload section error for store '{StorePath}': {error}"
107-
};
108-
Log.Debug (message);
109-
} else if (elfOffset >= 0) {
110-
StoreStream.Seek ((long)elfOffset, SeekOrigin.Begin);
111-
magic = reader.ReadUInt32 ();
112+
MaybeLogError (error);
113+
114+
(elfOffset, _, error) = Utils.FindELFPayloadSectionOffsetAndSize (StoreStream);
115+
if (error != ELFPayloadError.None) {
116+
MaybeLogError (error);
117+
return false;
118+
}
112119
}
120+
121+
StoreStream.Seek ((long)elfOffset, SeekOrigin.Begin);
122+
magic = reader.ReadUInt32 ();
113123
}
114124

115125
if (magic != Utils.ASSEMBLY_STORE_MAGIC) {
@@ -129,6 +139,15 @@ protected override bool IsSupported ()
129139

130140
header = new Header (magic, version, entry_count, index_entry_count, index_size);
131141
return true;
142+
143+
void MaybeLogError (ELFPayloadError error)
144+
{
145+
if (error == ELFPayloadError.None) {
146+
return;
147+
}
148+
149+
Log.Debug (PayloadErrorToString (error));
150+
}
132151
}
133152

134153
protected override void Prepare ()

tools/assembly-store-reader-mk2/AssemblyStore/Utils.cs

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using ELFSharp.ELF;
66
using ELFSharp.ELF.Sections;
7+
using Xamarin.Android.Tasks;
78
using Xamarin.Tools.Zip;
89

910
namespace Xamarin.Android.AssemblyStore;
@@ -29,31 +30,28 @@ static class Utils
2930

3031
public static readonly ArrayPool<byte> BytePool = ArrayPool<byte>.Shared;
3132

32-
public static (ulong offset, ulong size, ELFPayloadError error) FindELFPayloadSectionOffsetAndSize (Stream stream)
33+
static (bool is64, IELF? elf, ELFPayloadError error) TryOpenELF (Stream stream)
3334
{
35+
bool is64 = false;
3436
stream.Seek (0, SeekOrigin.Begin);
3537
Class elfClass = ELFReader.CheckELFType (stream);
3638
if (elfClass == Class.NotELF) {
37-
return ReturnError (null, ELFPayloadError.NotELF);
39+
return ReturnError (is64, null, ELFPayloadError.NotELF);
3840
}
3941

4042
if (!ELFReader.TryLoad (stream, shouldOwnStream: false, out IELF? elf)) {
41-
return ReturnError (elf, ELFPayloadError.LoadFailed);
43+
return ReturnError (is64, elf, ELFPayloadError.LoadFailed);
4244
}
4345

4446
if (elf.Type != FileType.SharedObject) {
45-
return ReturnError (elf, ELFPayloadError.NotSharedLibrary);
47+
return ReturnError (is64, elf, ELFPayloadError.NotSharedLibrary);
4648
}
4749

4850
if (elf.Endianess != ELFSharp.Endianess.LittleEndian) {
49-
return ReturnError (elf, ELFPayloadError.NotLittleEndian);
50-
}
51-
52-
if (!elf.TryGetSection ("payload", out ISection? payloadSection)) {
53-
return ReturnError (elf, ELFPayloadError.NoPayloadSection);
51+
return ReturnError (is64, elf, ELFPayloadError.NotLittleEndian);
5452
}
5553

56-
bool is64 = elf.Machine switch {
54+
is64 = elf.Machine switch {
5755
Machine.ARM => false,
5856
Machine.Intel386 => false,
5957

@@ -63,6 +61,51 @@ public static (ulong offset, ulong size, ELFPayloadError error) FindELFPayloadSe
6361
_ => throw new NotSupportedException ($"Unsupported ELF architecture '{elf.Machine}'")
6462
};
6563

64+
return (is64, elf, ELFPayloadError.None);
65+
66+
(bool is64, IELF? elf, ELFPayloadError error) ReturnError (bool is64, IELF? elf, ELFPayloadError error)
67+
{
68+
elf?.Dispose ();
69+
70+
return (is64, null, error);
71+
}
72+
}
73+
74+
public static (ulong offset, ulong size, ELFPayloadError error) FindEmbeddedStoreOffsetAndSize (Stream stream)
75+
{
76+
(bool is64, IELF? elf, ELFPayloadError error) = TryOpenELF (stream);
77+
if (elf == null || error != ELFPayloadError.None) {
78+
return ReturnError (elf, error);
79+
}
80+
81+
const string SymbolName = "embedded_assembly_store";
82+
ISymbolTable? dynsym = ELFHelper.GetSymbolTable (elf, ".dynsym");
83+
if (is64) {
84+
SymbolEntry<ulong>? symbol = ELFHelper.FindSymbol<ulong> (dynsym, SymbolName);
85+
if (symbol != null) {
86+
return (symbol.Value, symbol.Size, ELFPayloadError.None);
87+
}
88+
} else {
89+
SymbolEntry<uint>? symbol = ELFHelper.FindSymbol<uint> (dynsym, SymbolName);
90+
if (symbol != null) {
91+
return ((ulong)symbol.Value, (ulong)symbol.Size, ELFPayloadError.None);
92+
}
93+
}
94+
95+
return (0, 0, ELFPayloadError.NoEmbeddedStore);
96+
}
97+
98+
public static (ulong offset, ulong size, ELFPayloadError error) FindELFPayloadSectionOffsetAndSize (Stream stream)
99+
{
100+
(bool is64, IELF? elf, ELFPayloadError error) = TryOpenELF (stream);
101+
if (elf == null || error != ELFPayloadError.None) {
102+
return ReturnError (elf, error);
103+
}
104+
105+
if (!elf.TryGetSection ("payload", out ISection? payloadSection)) {
106+
return ReturnError (elf, ELFPayloadError.NoPayloadSection);
107+
}
108+
66109
ulong offset;
67110
ulong size;
68111

@@ -84,13 +127,13 @@ public static (ulong offset, ulong size, ELFPayloadError error) FindELFPayloadSe
84127
{
85128
return ((ulong)payload.Offset, (ulong)payload.Size);
86129
}
130+
}
87131

88-
(ulong offset, ulong size, ELFPayloadError error) ReturnError (IELF? elf, ELFPayloadError error)
89-
{
90-
elf?.Dispose ();
132+
static (ulong offset, ulong size, ELFPayloadError error) ReturnError (IELF? elf, ELFPayloadError error)
133+
{
134+
elf?.Dispose ();
91135

92-
return (0, 0, error);
93-
}
136+
return (0, 0, error);
94137
}
95138

96139
public static (FileFormat format, FileInfo? info) DetectFileFormat (string path)

tools/assembly-store-reader-mk2/assembly-store-reader.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
<ItemGroup>
2626
<Compile Include="..\..\src\Xamarin.Android.Build.Tasks\Utilities\MonoAndroidHelper.Basic.cs" />
27+
<Compile Include="..\..\src\Xamarin.Android.Build.Tasks\Utilities\ELFHelper.Basic.cs" />
2728
</ItemGroup>
2829

2930
<ItemGroup>

0 commit comments

Comments
 (0)