@@ -537,6 +537,157 @@ the pipeline. Here is a quick summary of the various options:
537
537
When printing IR for functions for print-[ before|after] -all options, Only
538
538
print the IR for functions whose name is in this comma separated list.
539
539
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
+
540
691
## Bisecting Compiler Errors
541
692
542
693
### Bisecting on SIL optimizer pass counts to identify optimizer bugs
0 commit comments