Skip to content

Commit a2cb5a8

Browse files
Merge pull request #35639 from varungandhi-apple/vg-doc-asm-obj-debugging
[docs] Document tips for debugging assembly & object code.
2 parents 7c355cc + 7dcaf5c commit a2cb5a8

File tree

1 file changed

+151
-0
lines changed

1 file changed

+151
-0
lines changed

docs/DebuggingTheCompiler.md

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,157 @@ the pipeline. Here is a quick summary of the various options:
537537
When printing IR for functions for print-[before|after]-all options, Only
538538
print the IR for functions whose name is in this comma separated list.
539539

540+
## Debugging assembly and object code
541+
542+
Understanding layout of compiler-generated metadata
543+
can sometimes involve looking at assembly and object code.
544+
545+
### Working with a single file
546+
547+
Here's how to generate assembly or object code:
548+
549+
```
550+
# Emit assembly in Intel syntax (AT&T syntax is the default)
551+
swiftc tmp.swift -emit-assembly -Xllvm -x86-asm-syntax=intel -o tmp.S
552+
553+
# Emit object code
554+
swiftc tmp.swift -emit-object -o tmp.o
555+
```
556+
557+
Understanding mangled names can be hard though: `swift demangle` to the rescue!
558+
559+
```
560+
swiftc tmp.swift -emit-assembly -Xllvm -x86-asm-syntax=intel -o - \
561+
| swift demangle > tmp-demangled.S
562+
563+
swiftc tmp.swift -emit-object -o tmp.o
564+
565+
# Look at where different symbols are located, sorting by address (-n)
566+
# and displaying section names (-m)
567+
nm -n -m tmp.o | swift demangle > tmp.txt
568+
569+
# Inspect disassembly of an existing dylib (AT&T syntax is the default)
570+
objdump -d -macho --x86-asm-syntax=intel /path/to/libcake.dylib \
571+
| swift demangle > libcake.S
572+
```
573+
574+
### Working with multiple files
575+
576+
Some bugs only manifest in WMO, and may involve complicated Xcode projects.
577+
Moreover, Xcode may be passing arguments via `-filelist`
578+
and expecting outputs via `-output-filelist`, and those file lists
579+
may be in temporary directories.
580+
581+
If you want to inspect assembly or object code for individual files when
582+
compiling under WMO, you can mimic this by doing the following:
583+
584+
```
585+
# Assuming all .swift files from the MyProject/Sources directory
586+
# need to be included
587+
find MyProject/Sources -name '*.swift' -type f > input-files.txt
588+
589+
# In some cases, projects may use multiple files with the same
590+
# name but in different directories (for different schemes),
591+
# which can be a problem. Having a file list makes working around
592+
# this convenient as you can manually manually edit out the files
593+
# that are not of interest at this stage.
594+
595+
mkdir Output
596+
597+
# 1. -output-filelist doesn't recreate a subdirectory structure,
598+
# so first strip out directories
599+
# 2. map .swift files to assembly files
600+
sed -e 's|.*/|Output/|;s|\.swift|.S|' input-files.txt > output-files.txt
601+
602+
# Save command-line arguments from Xcode's 'CompileSwiftSources' phase in
603+
# the build log to a file for convenience, say args.txt.
604+
#
605+
# -sdk /path/to/sdk <... other args ...>
606+
607+
xcrun swift-frontend @args.txt \
608+
-filelist input-files.txt \
609+
-output-filelist output-files.txt \
610+
-O -whole-module-optimization \
611+
-emit-assembly
612+
```
613+
614+
If you are manually calling `swift-frontend` without an Xcode invocation to
615+
use as a template, you will need to at least add
616+
`-sdk "$(xcrun --show-sdk-path macosx)"` (if compiling for macOS),
617+
and `-I /path/to/includedir` to include necessary swift modules and interfaces.
618+
619+
### Working with multi-architecture binaries
620+
621+
On macOS, one might be interested in debugging multi-architecture binaries
622+
such as [universal binaries][]. By default `nm` will show symbols from all
623+
architectures, so a universal binary might look funny due to two copies of
624+
everything. Use `nm -arch` to look at a specific architecture:
625+
626+
```
627+
nm -n -m -arch x86_64 path/to/libcake.dylib | swift demangle
628+
```
629+
630+
[universal binaries]: https://en.wikipedia.org/wiki/Universal_binary
631+
632+
### Other helpful tools
633+
634+
TODO: This section should mention information about non-macOS platforms:
635+
maybe we can have a table with rows for use cases and columns for
636+
platforms (macOS, Linux, Windows), and the cells would be tool names.
637+
We could also mention platforms next to the tool names.
638+
639+
In the previous sub-sections, we've seen how using different tools can
640+
make working with assembly and object code much nicer. Here is a short
641+
listing of commonly used tools on macOS, along with some example use cases:
642+
643+
- Miscellaneous:
644+
- `strings`: Find printable strings in a binary file.
645+
- Potential use cases: If you're building a binary in multiple configurations,
646+
and forgot which binary corresponds to which configuration, you can look
647+
through the output of `strings` to identify differences.
648+
- `c++filt`: The C++ equivalent of `swift-demangle`.
649+
- Potential use cases: Looking at the generated code for the
650+
Swift runtime, investigating C++ interop issues.
651+
652+
- Linking:
653+
- `libtool`: A tool to create static and dynamic libraries. Generally, it's
654+
easier to instead ask `swiftc` to link files, but potentially handy as
655+
a higher-level alternative to `ld`, `ar` and `lipo`.
656+
657+
- Debug info:
658+
- `dwarfdump`: Extract debug info in human-readable form.
659+
- Potential use cases: If you want to quickly check if two binaries
660+
are identical, you can compare their UUIDs. For on-disk binaries,
661+
you can obtain the UUID using `dwarfdump --uuid` For binaries
662+
loaded by a running application, you can obtain the UUID using
663+
`image list` in LLDB.
664+
- `objdump`: Dump object files.
665+
Some examples of using `objdump` are documented in the previous subsection.
666+
If you have a Swift compiler build, you can use `llvm-objdump` from
667+
`$LLVM_BUILD_DIR/bin` instead of using the system `objdump`.
668+
669+
Compared to other tools on this list, `objdump` packs a LOT of
670+
functionality; it can show information about sections, relocations
671+
and more. It also supports many flags to format and filter the output.
672+
673+
- Linker information (symbol table, sections, binding):
674+
- `nm`: Display symbol tables.
675+
Some examples of using `nm` are documented in the previous subsection.
676+
- `size`: Get high-level information about sections in a binary,
677+
such as the sizes of sections and where they are located.
678+
- `dyldinfo`: Display information used by dyld, such as which dylibs
679+
an image depends on.
680+
- `install_name_tool`: Change the name for a dynamic shared library,
681+
and query or modify the runpath search paths (aka 'rpaths') it uses.
682+
683+
- Multi-architecture binaries:
684+
- `lipo`: A tool that can be used to create, inspect and dissect
685+
[universal binaries][universal binaries].
686+
- Potential use cases: If you have a universal binary on an
687+
Apple Silicon Mac, but want to quickly test if the issue would reproduce
688+
on `x86_64`, you can extract the `x86_64` slice by using `lipo`.
689+
The `x86_64` binary will automatically run under Rosetta 2.
690+
540691
## Bisecting Compiler Errors
541692

542693
### Bisecting on SIL optimizer pass counts to identify optimizer bugs

0 commit comments

Comments
 (0)