Skip to content

Commit b35028e

Browse files
committed
Extract debug symbols at link time
1 parent 257aedc commit b35028e

File tree

3 files changed

+87
-11
lines changed

3 files changed

+87
-11
lines changed

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeRuntime.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Contains code to build and link the native runtime at application build time.
4343
LinkLibraries="@(_RequiredLinkLibraries)"
4444
OutputRuntimes="@(_UnifiedNativeRuntime)"
4545
SupportedAbis="@(_BuildTargetAbis)"
46+
SaveDebugSymbols="true"
4647
/>
4748
</Target>
4849
</Project>

src/Xamarin.Android.Build.Tasks/Tasks/LinkNativeRuntime.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ public class LinkNativeRuntime : AndroidAsyncTask
3636
[Required]
3737
public ITaskItem[] SupportedAbis { get; set; }
3838

39+
public bool SaveDebugSymbols { get; set; }
40+
3941
public override System.Threading.Tasks.Task RunTaskAsync ()
4042
{
4143
return this.WhenAll (SupportedAbis, LinkRuntime);
@@ -51,7 +53,9 @@ void LinkRuntime (ITaskItem abiItem)
5153
soname = soname.Substring (3);
5254
}
5355

54-
var linker = new NativeLinker (Log, abi, soname, AndroidBinUtilsDirectory, IntermediateOutputPath, CancellationToken, Cancel);
56+
var linker = new NativeLinker (Log, abi, soname, AndroidBinUtilsDirectory, IntermediateOutputPath, CancellationToken, Cancel) {
57+
SaveDebugSymbols = SaveDebugSymbols,
58+
};
5559
linker.Link (
5660
outputRuntime,
5761
GetAbiItems (NativeObjectFiles, "_NativeAssemblyTarget", abi),

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

Lines changed: 81 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class NativeLinker
3535
readonly TaskLoggingHelper log;
3636
readonly string abi;
3737
readonly string ld;
38+
readonly string objcopy;
3839
readonly string intermediateDir;
3940
readonly CancellationToken? cancellationToken;
4041
readonly Action? cancelTask;
@@ -52,6 +53,7 @@ public NativeLinker (TaskLoggingHelper log, string abi, string soname, string bi
5253
this.cancelTask = cancelTask;
5354

5455
ld = Path.Combine (binutilsDir, MonoAndroidHelper.GetExecutablePath (binutilsDir, "ld"));
56+
objcopy = Path.Combine (binutilsDir, MonoAndroidHelper.GetExecutablePath (binutilsDir, "llvm-objcopy"));
5557

5658
extraArgs.Add ($"-soname {soname}");
5759

@@ -142,6 +144,11 @@ public bool Link (ITaskItem outputLibraryPath, List<ITaskItem> objectFiles, List
142144
watch.Stop ();
143145
log.LogDebugMessage ($"[{Path.GetFileName (outputLibraryPath.ItemSpec)} link time] {watch.Elapsed}");
144146

147+
if (!ret || !SaveDebugSymbols) {
148+
return ret;
149+
}
150+
151+
ret = ExtractDebugSymbols (outputLibraryPath);
145152
return ret;
146153

147154
void WriteFilesToResponseFile (StreamWriter sw, List<ITaskItem> files)
@@ -190,12 +197,81 @@ void EnsureCorrectAbi (List<ITaskItem> items)
190197
}
191198
}
192199

200+
bool ExtractDebugSymbols (ITaskItem outputSharedLibrary)
201+
{
202+
var stdoutLines = new List<string> ();
203+
var stderrLines = new List<string> ();
204+
205+
string sourceLib = outputSharedLibrary.ItemSpec;
206+
string sourceLibQuoted = MonoAndroidHelper.QuoteFileNameArgument (sourceLib);
207+
string destLib = Path.Combine (Path.GetDirectoryName (sourceLib), $"{Path.GetFileNameWithoutExtension (sourceLib)}.dbg.so");
208+
string destLibQuoted = MonoAndroidHelper.QuoteFileNameArgument (destLib);
209+
210+
var args = new List<string> {
211+
"--only-keep-debug",
212+
sourceLibQuoted,
213+
destLibQuoted,
214+
};
215+
216+
if (!RunCommand ("Extract Debug Info", objcopy, args, stdoutLines, stderrLines)) {
217+
LogFailure ();
218+
return false;
219+
}
220+
221+
stdoutLines.Clear ();
222+
stderrLines.Clear ();
223+
args.Clear ();
224+
args.Add ("--strip-debug");
225+
args.Add ("--strip-unneeded");
226+
args.Add (sourceLibQuoted);
227+
228+
if (!RunCommand ("Strip Debug Info", objcopy, args, stdoutLines, stderrLines)) {
229+
LogFailure ();
230+
return false;
231+
}
232+
233+
stdoutLines.Clear ();
234+
stderrLines.Clear ();
235+
args.Clear ();
236+
args.Add ($"--add-gnu-debuglink={destLibQuoted}");
237+
args.Add (sourceLibQuoted);
238+
239+
if (!RunCommand ("Add Debug Info Link", objcopy, args, stdoutLines, stderrLines)) {
240+
LogFailure ();
241+
return false;
242+
}
243+
244+
return true;
245+
246+
void LogFailure ()
247+
{
248+
var sb = MonoAndroidHelper.MergeStdoutAndStderrMessages (stdoutLines, stderrLines);
249+
// TODO: consider making it a warning
250+
// TODO: make it a coded message
251+
log.LogError ("Failed to extract debug info", Path.GetFileName (sourceLib), sb.ToString ());
252+
}
253+
}
254+
193255
bool RunLinker (List<string> args, ITaskItem outputSharedLibrary)
256+
{
257+
var stdoutLines = new List<string> ();
258+
var stderrLines = new List<string> ();
259+
260+
if (!RunCommand ("Native Linker", ld, args, stdoutLines, stderrLines)) {
261+
var sb = MonoAndroidHelper.MergeStdoutAndStderrMessages (stdoutLines, stderrLines);
262+
log.LogCodedError ("XA3007", Properties.Resources.XA3007, Path.GetFileName (outputSharedLibrary.ItemSpec), sb.ToString ());
263+
return false;
264+
}
265+
266+
return true;
267+
}
268+
269+
bool RunCommand (string label, string binaryPath, List<string> args, List<string> stdoutLines, List<string> stderrLines)
194270
{
195271
using var stdout_completed = new ManualResetEvent (false);
196272
using var stderr_completed = new ManualResetEvent (false);
197273
var psi = new ProcessStartInfo () {
198-
FileName = ld,
274+
FileName = binaryPath,
199275
Arguments = String.Join (" ", args),
200276
UseShellExecute = false,
201277
RedirectStandardOutput = true,
@@ -204,16 +280,13 @@ bool RunLinker (List<string> args, ITaskItem outputSharedLibrary)
204280
WindowStyle = ProcessWindowStyle.Hidden,
205281
};
206282

207-
string linkerName = Path.GetFileName (ld);
208-
log.LogDebugMessage ($"[Native Linker] {psi.FileName} {psi.Arguments}");
209-
210-
var stdoutLines = new List<string> ();
211-
var stderrLines = new List<string> ();
283+
string binaryName = Path.GetFileName (ld);
284+
log.LogDebugMessage ($"[{label}] {psi.FileName} {psi.Arguments}");
212285

213286
using var proc = new Process ();
214287
proc.OutputDataReceived += (s, e) => {
215288
if (e.Data != null) {
216-
OnOutputData (linkerName, s, e);
289+
OnOutputData (binaryName, s, e);
217290
stdoutLines.Add (e.Data);
218291
} else {
219292
stdout_completed.Set ();
@@ -222,7 +295,7 @@ bool RunLinker (List<string> args, ITaskItem outputSharedLibrary)
222295

223296
proc.ErrorDataReceived += (s, e) => {
224297
if (e.Data != null) {
225-
OnErrorData (linkerName, s, e);
298+
OnErrorData (binaryName, s, e);
226299
stderrLines.Add (e.Data);
227300
} else {
228301
stderr_completed.Set ();
@@ -245,8 +318,6 @@ bool RunLinker (List<string> args, ITaskItem outputSharedLibrary)
245318
}
246319

247320
if (proc.ExitCode != 0) {
248-
var sb = MonoAndroidHelper.MergeStdoutAndStderrMessages (stdoutLines, stderrLines);
249-
log.LogCodedError ("XA3007", Properties.Resources.XA3007, Path.GetFileName (outputSharedLibrary.ItemSpec), sb.ToString ());
250321
cancelTask?.Invoke ();
251322
return false;
252323
}

0 commit comments

Comments
 (0)