Added support for profiling stripped Mach-O binaries.
diff --git a/README.md b/README.md
index da8e515..3972bdb 100644
--- a/README.md
+++ b/README.md
@@ -294,27 +294,26 @@
 easy mistake to make, and one that I made several times even
 as Bloaty's author!).
 
-Make sure you are compiling with build IDs enabled.  For gcc
-this happens automatically, but [Clang decided not to make
-this the default, since it makes the link
-slower](http://releases.llvm.org/3.9.0/tools/clang/docs/ReleaseNotes.html#major-new-features).
-For Clang add `-Wl,--build-id` to your link line.  (If you
-want a slightly faster link and don't care about
-reproducibility, you can use `-Wl,--build-id=uuid` instead).
-
-Then you can strip the binary and uses the unstripped binary
-as your debug file.  For example, with bloaty itself:
+If your binary has a build ID, then using separate debug
+files is as simple as:
 
 ```
 $ cp bloaty bloaty.stripped
 $ strip bloaty.stripped
-$ ./bloaty -d compileunits --debug-file=bloaty bloaty.stripped
+$ ./bloaty -d symbols --debug-file=bloaty bloaty.stripped
 ```
 
-It is also possible to remove debug sections only (see
-`objcopy --strip-debug`) while keeping the symbol table.
-You can also create debug file that contain *only* debug
-info (see `objcopy --only-keep-debug`).
+Some format-specific notes follow.
+
+## ELF
+
+For ELF, make sure you are compiling with build IDs enabled.
+With gcc this happens automatically, but [Clang decided not
+to make this the default, since it makes the link
+slower](http://releases.llvm.org/3.9.0/tools/clang/docs/ReleaseNotes.html#major-new-features).
+For Clang add `-Wl,--build-id` to your link line.  (If you
+want a slightly faster link and don't care about
+reproducibility, you can use `-Wl,--build-id=uuid` instead).
 
 Bloaty does not currently support the GNU debuglink or
 looking up debug files by build ID, [which are the methods
@@ -323,6 +322,17 @@
 If there are use cases where Bloaty's `--debug-file` option
 won't work, we can reconsider implementing these.
 
+## Mach-O
+
+Mach-O files always have build IDs (as far as I can tell),
+so no special configuration is needed to make sure you get
+them.
+
+TODO: Mach-O puts debug info in separate files, which are
+created using `dsymutil`.  DWARF is not yet supported for
+Mach-O, but once it is then `--debug-file` will be necessary
+to help Bloaty find these separate debug files also.
+
 # Configuration Files
 
 Any options that you can specify on the command-line, you
diff --git a/src/macho.cc b/src/macho.cc
index a027952..3058774 100644
--- a/src/macho.cc
+++ b/src/macho.cc
@@ -416,7 +416,8 @@
       });
 }
 
-void ParseSymbolsFromSymbolTable(string_view command_data, string_view file_data, RangeSink* sink) {
+void ParseSymbolsFromSymbolTable(string_view command_data,
+                                 string_view file_data, RangeSink* sink) {
   auto symtab_cmd = GetStructPointer<symtab_command>(command_data);
 
   // TODO(haberman): use 32-bit symbol size where appropriate.
@@ -439,9 +440,9 @@
   }
 }
 
-void ParseSymbols(RangeSink* sink) {
+void ParseSymbols(string_view file_data, RangeSink* sink) {
   ForEachLoadCommand(
-      sink->input_file().data(), sink,
+      file_data, sink,
       [sink](uint32_t cmd, string_view command_data, string_view file_data) {
         switch (cmd) {
           case LC_SYMTAB:
@@ -478,8 +479,24 @@
       : ObjectFile(std::move(file_data)) {}
 
   std::string GetBuildId() const override {
-    // TODO(haberman): implement.
-    return std::string();
+    std::string id;
+
+    ForEachLoadCommand(
+        file_data().data(), nullptr,
+        [&id](uint32_t cmd, string_view command_data,
+              string_view /* file_data */) {
+          if (cmd == LC_UUID) {
+            auto uuid_cmd =
+                GetStructPointerAndAdvance<uuid_command>(&command_data);
+            if (!command_data.empty()) {
+              THROWF("Unexpected excess uuid data: $0", command_data.size());
+            }
+            id.resize(sizeof(uuid_cmd->uuid));
+            memcpy(&id[0], &uuid_cmd->uuid[0], sizeof(uuid_cmd->uuid));
+          }
+        });
+
+    return id;
   }
 
   void ProcessFile(const std::vector<RangeSink*>& sinks) const override {
@@ -493,7 +510,7 @@
         case DataSource::kRawSymbols:
         case DataSource::kShortSymbols:
         case DataSource::kFullSymbols:
-          ParseSymbols(sink);
+          ParseSymbols(debug_file().file_data().data(), sink);
           break;
         case DataSource::kArchiveMembers:
         case DataSource::kCompileUnits: