Added some debugging and fixed some bugs.
diff --git a/src/bloaty.cc b/src/bloaty.cc
index 73c47d0..58fb7af 100644
--- a/src/bloaty.cc
+++ b/src/bloaty.cc
@@ -258,6 +258,7 @@
       return std::string(symbol);
     }
   } else {
+    printf("Unexpected source: %d\n", (int)source);
     BLOATY_UNREACHABLE();
   }
 }
@@ -867,12 +868,12 @@
   outputs_.push_back(std::make_pair(map, munger));
 }
 
-void RangeSink::AddFileRange(string_view name, uint64_t fileoff,
-                             uint64_t filesize) {
+void RangeSink::AddFileRange(const char* analyzer, string_view name,
+                             uint64_t fileoff, uint64_t filesize) {
   if (verbose_level > 2) {
-    fprintf(stdout, "[%s] AddFileRange(%.*s, %" PRIx64 ", %" PRIx64 ")\n",
-            GetDataSourceLabel(data_source_), (int)name.size(), name.data(),
-            fileoff, filesize);
+    fprintf(stdout, "[%s, %s] AddFileRange(%.*s, %" PRIx64 ", %" PRIx64 ")\n",
+            GetDataSourceLabel(data_source_), analyzer, (int)name.size(),
+            name.data(), fileoff, filesize);
   }
   for (auto& pair : outputs_) {
     const std::string label = pair.second->Munge(name);
@@ -885,14 +886,16 @@
   }
 }
 
-void RangeSink::AddFileRangeFor(uint64_t label_from_vmaddr,
+void RangeSink::AddFileRangeFor(const char* analyzer,
+                                uint64_t label_from_vmaddr,
                                 string_view file_range) {
   uint64_t file_offset = file_range.data() - file_->data().data();
   if (verbose_level > 2) {
     fprintf(stdout,
-            "[%s] AddFileRangeFor(%" PRIx64 ", [%" PRIx64 ", %" PRIx64 "])\n",
-            GetDataSourceLabel(data_source_), label_from_vmaddr, file_offset,
-            file_range.size());
+            "[%s, %s] AddFileRangeFor(%" PRIx64 ", [%" PRIx64 ", %" PRIx64
+            "])\n",
+            GetDataSourceLabel(data_source_), analyzer, label_from_vmaddr,
+            file_offset, file_range.size());
   }
   assert(translator_);
   for (auto& pair : outputs_) {
@@ -908,14 +911,13 @@
   }
 }
 
-void RangeSink::AddVMRangeFor(uint64_t label_from_vmaddr, uint64_t addr,
-                              uint64_t size) {
+void RangeSink::AddVMRangeFor(const char* analyzer, uint64_t label_from_vmaddr,
+                              uint64_t addr, uint64_t size) {
   if (verbose_level > 2) {
     fprintf(stdout,
-            "[%s] AddVMRangeFor(%" PRIx64 ", [%" PRIx64 ", %" PRIx64 "])\n",
-            GetDataSourceLabel(data_source_), label_from_vmaddr, addr, size);
-    fprintf(stdout, "Translation map:\n%s",
-            translator_->file_map.DebugString().c_str());
+            "[%s, %s] AddVMRangeFor(%" PRIx64 ", [%" PRIx64 ", %" PRIx64 "])\n",
+            GetDataSourceLabel(data_source_), analyzer, label_from_vmaddr, addr,
+            size);
   }
   assert(translator_);
   for (auto& pair : outputs_) {
@@ -930,12 +932,12 @@
   }
 }
 
-void RangeSink::AddVMRange(uint64_t vmaddr, uint64_t vmsize,
-                           const std::string& name) {
+void RangeSink::AddVMRange(const char* analyzer, uint64_t vmaddr,
+                           uint64_t vmsize, const std::string& name) {
   if (verbose_level > 2) {
-    fprintf(stdout, "[%s] AddVMRange(%.*s, %" PRIx64 ", %" PRIx64 ")\n",
-            GetDataSourceLabel(data_source_), (int)name.size(), name.data(),
-            vmaddr, vmsize);
+    fprintf(stdout, "[%s, %s] AddVMRange(%.*s, %" PRIx64 ", %" PRIx64 ")\n",
+            GetDataSourceLabel(data_source_), analyzer, (int)name.size(),
+            name.data(), vmaddr, vmsize);
   }
   assert(translator_);
   for (auto& pair : outputs_) {
@@ -945,26 +947,29 @@
   }
 }
 
-void RangeSink::AddVMRangeAllowAlias(uint64_t vmaddr, uint64_t size,
-                                     const std::string& name) {
+void RangeSink::AddVMRangeAllowAlias(const char* analyzer, uint64_t vmaddr,
+                                     uint64_t size, const std::string& name) {
   // TODO: maybe track alias (but what would we use it for?)
   // TODO: verify that it is in fact an alias.
-  AddVMRange(vmaddr, size, name);
+  AddVMRange(analyzer, vmaddr, size, name);
 }
 
-void RangeSink::AddVMRangeIgnoreDuplicate(uint64_t vmaddr, uint64_t vmsize,
+void RangeSink::AddVMRangeIgnoreDuplicate(const char* analyzer, uint64_t vmaddr,
+                                          uint64_t vmsize,
                                           const std::string& name) {
   // TODO suppress warning that AddVMRange alone might trigger.
-  AddVMRange(vmaddr, vmsize, name);
+  AddVMRange(analyzer, vmaddr, vmsize, name);
 }
 
-void RangeSink::AddRange(string_view name, uint64_t vmaddr, uint64_t vmsize,
-                         uint64_t fileoff, uint64_t filesize) {
+void RangeSink::AddRange(const char* analyzer, string_view name,
+                         uint64_t vmaddr, uint64_t vmsize, uint64_t fileoff,
+                         uint64_t filesize) {
   if (verbose_level > 2) {
-    fprintf(stdout, "[%s] AddRange(%.*s, %" PRIx64 ", %" PRIx64 ", %" PRIx64
+    fprintf(stdout,
+            "[%s, %s] AddRange(%.*s, %" PRIx64 ", %" PRIx64 ", %" PRIx64
             ", %" PRIx64 ")\n",
-            GetDataSourceLabel(data_source_), (int)name.size(), name.data(),
-            vmaddr, vmsize, fileoff, filesize);
+            GetDataSourceLabel(data_source_), analyzer, (int)name.size(),
+            name.data(), vmaddr, vmsize, fileoff, filesize);
   }
   for (auto& pair : outputs_) {
     const std::string label = pair.second->Munge(name);
@@ -1106,6 +1111,7 @@
   }
 
   void ScanAndRollupFiles(const std::vector<std::unique_ptr<ObjectFile>>& files,
+                          std::vector<std::string>* build_ids,
                           Rollup* rollup) const;
   void ScanAndRollupFile(ObjectFile* file, Rollup* rollup,
                          std::string* out_build_id) const;
@@ -1333,11 +1339,13 @@
   for (auto sink : filename_sink_ptrs) {
     maps.base_map()->vm_map.ForEachRange(
         [sink](uint64_t start, uint64_t length) {
-          sink->AddVMRange(start, length, sink->input_file().filename());
+          sink->AddVMRange("inputfile_vmcopier", start, length,
+                           sink->input_file().filename());
         });
     maps.base_map()->file_map.ForEachRange(
         [sink](uint64_t start, uint64_t length) {
-          sink->AddFileRange(sink->input_file().filename(), start, length);
+          sink->AddFileRange("inputfile_filecopier",
+                             sink->input_file().filename(), start, length);
         });
   }
 
@@ -1349,13 +1357,14 @@
       RangeSink* from = sinks[i - 1].get();
       from->MapAtIndex(0).vm_map.ForEachRange([ranges_sink](uint64_t start,
                                                             uint64_t length) {
-        ranges_sink->AddVMRange(start, length,
+        ranges_sink->AddVMRange("rawrange_vmcopier", start, length,
                                 absl::StrCat("vm: [", absl::Hex(start), ", ",
                                              absl::Hex(start + length), "]"));
       });
       from->MapAtIndex(0).file_map.ForEachRange(
           [ranges_sink](uint64_t start, uint64_t length) {
             ranges_sink->AddFileRange(
+                "rawrange_filecopier",
                 absl::StrCat("file: [", absl::Hex(start), ", ",
                              absl::Hex(start + length), "]"),
                 start, length);
@@ -1380,7 +1389,8 @@
 
 void Bloaty::ScanAndRollupFiles(
     const std::vector<std::unique_ptr<ObjectFile>>& files,
-    Rollup* rollup) const {
+    std::vector<std::string>* build_ids,
+    Rollup * rollup) const {
   int num_cpus = std::thread::hardware_concurrency();
   int num_threads = std::min(num_cpus, static_cast<int>(files.size()));
 
@@ -1406,14 +1416,6 @@
     }, &thread_data[i]);
   }
 
-  // Create a copy of the debug_files_ member, so we can determine which (if
-  // any) debug files weren't used.  We copy it because we are in a const method
-  // so can't mutate debug_files_ directly.
-  std::map<std::string, const ObjectFile*> debug_files;
-  for (const auto& pair : debug_files_) {
-    debug_files[pair.first] = pair.second.get();
-  }
-
   for (int i = 0; i < num_threads; i++) {
     threads[i].join();
     PerThreadData* data = &thread_data[i];
@@ -1424,7 +1426,7 @@
     }
 
     if (!data->build_id.empty()) {
-      debug_files.erase(data->build_id);
+      build_ids->push_back(data->build_id);
     }
   }
 
@@ -1432,26 +1434,6 @@
   if (index.TryGetError(&error)) {
     THROW(error.c_str());
   }
-
-  if (!debug_files.empty()) {
-    std::string unused_debug;
-    for (const auto& pair : debug_files) {
-      unused_debug += absl::Substitute(
-          "$0   $1\n",
-          absl::BytesToHexString(pair.second->GetBuildId()).c_str(),
-          pair.second->file_data().filename().c_str());
-    }
-
-    std::string input_files;
-    for (const auto& file : files) {
-      input_files += absl::Substitute(
-          "$0   $1\n", absl::BytesToHexString(file->GetBuildId()).c_str(),
-          file->file_data().filename().c_str());
-    }
-    THROWF(
-        "Debug file(s) did not match any input file:\n$0\nInput Files:\n$1",
-        unused_debug.c_str(), input_files.c_str());
-  }
 }
 
 void Bloaty::ScanAndRollup(const Options& options, RollupOutput* output) {
@@ -1464,16 +1446,47 @@
   }
 
   Rollup rollup;
-  ScanAndRollupFiles(input_files_, &rollup);
+  std::vector<std::string> build_ids;
+  ScanAndRollupFiles(input_files_, &build_ids, &rollup);
 
   if (!base_files_.empty()) {
     Rollup base;
-    ScanAndRollupFiles(base_files_, &base);
+    ScanAndRollupFiles(base_files_, &build_ids, &base);
     rollup.Subtract(base);
     rollup.CreateDiffModeRollupOutput(&base, options, output);
   } else {
     rollup.CreateRollupOutput(options, output);
   }
+
+  for (const auto& build_id : build_ids) {
+    debug_files_.erase(build_id);
+  }
+
+  // Error out if some --debug-files were not used.
+  if (!debug_files_.empty()) {
+    std::string input_files;
+    std::string unused_debug;
+    for (const auto& pair : debug_files_) {
+      unused_debug += absl::Substitute(
+          "$0   $1\n",
+          absl::BytesToHexString(pair.second->GetBuildId()).c_str(),
+          pair.second->file_data().filename().c_str());
+    }
+
+    for (const auto& file : input_files_) {
+      input_files += absl::Substitute(
+          "$0   $1\n", absl::BytesToHexString(file->GetBuildId()).c_str(),
+          file->file_data().filename().c_str());
+    }
+    for (const auto& file : base_files_) {
+      input_files += absl::Substitute(
+          "$0   $1\n", absl::BytesToHexString(file->GetBuildId()).c_str(),
+          file->file_data().filename().c_str());
+    }
+    THROWF(
+        "Debug file(s) did not match any input file:\n$0\nInput Files:\n$1",
+        unused_debug.c_str(), input_files.c_str());
+  }
 }
 
 void Bloaty::DisassembleFunction(string_view function, const Options& options,
diff --git a/src/bloaty.h b/src/bloaty.h
index 78fc557..8e36592 100644
--- a/src/bloaty.h
+++ b/src/bloaty.h
@@ -146,26 +146,28 @@
   // If vmsize or filesize is zero, this mapping is presumed not to exist in
   // that domain.  For example, .bss mappings don't exist in the file, and
   // .debug_* mappings don't exist in memory.
-  void AddRange(absl::string_view name, uint64_t vmaddr, uint64_t vmsize,
-                uint64_t fileoff, uint64_t filesize);
+  void AddRange(const char* analyzer, absl::string_view name, uint64_t vmaddr,
+                uint64_t vmsize, uint64_t fileoff, uint64_t filesize);
 
-  void AddRange(absl::string_view name, uint64_t vmaddr, uint64_t vmsize,
-                      absl::string_view file_range) {
-    AddRange(name, vmaddr, vmsize, file_range.data() - file_->data().data(),
-             file_range.size());
+  void AddRange(const char* analyzer, absl::string_view name, uint64_t vmaddr,
+                uint64_t vmsize, absl::string_view file_range) {
+    AddRange(analyzer, name, vmaddr, vmsize,
+             file_range.data() - file_->data().data(), file_range.size());
   }
 
-  void AddFileRange(absl::string_view name,
+  void AddFileRange(const char* analyzer, absl::string_view name,
                     uint64_t fileoff, uint64_t filesize);
 
   // Like AddFileRange(), but the label is whatever label was previously
   // assigned to VM address |label_from_vmaddr|.  If no existing label is
   // assigned to |label_from_vmaddr|, this function does nothing.
-  void AddFileRangeFor(uint64_t label_from_vmaddr,
+  void AddFileRangeFor(const char* analyzer, uint64_t label_from_vmaddr,
                        absl::string_view file_range);
-  void AddVMRangeFor(uint64_t label_from_vmaddr, uint64_t addr, uint64_t size);
+  void AddVMRangeFor(const char* analyzer, uint64_t label_from_vmaddr,
+                     uint64_t addr, uint64_t size);
 
-  void AddFileRange(absl::string_view name, absl::string_view file_range) {
+  void AddFileRange(const char* analyzer, absl::string_view name,
+                    absl::string_view file_range) {
     // When separate debug files are being used, the DWARF analyzer will try to
     // add sections of the debug file.  We want to prevent this because we only
     // want to profile the main file (not the debug file), so we filter these
@@ -173,7 +175,7 @@
     // useless work being done.  We may want to avoid doing this useless work in
     // the first place.
     if (FileContainsPointer(file_range.data())) {
-      AddFileRange(name, file_range.data() - file_->data().data(),
+      AddFileRange(analyzer, name, file_range.data() - file_->data().data(),
                    file_range.size());
     }
   }
@@ -182,7 +184,8 @@
 
   // Adds a region to the memory map.  It should not overlap any previous
   // region added with Add(), but it should overlap the base memory map.
-  void AddVMRange(uint64_t vmaddr, uint64_t vmsize, const std::string& name);
+  void AddVMRange(const char* analyzer, uint64_t vmaddr, uint64_t vmsize,
+                  const std::string& name);
 
   // Like Add(), but allows that this addr/size might have previously been added
   // already under a different name.  If so, this name becomes an alias of the
@@ -190,8 +193,8 @@
   //
   // This is for things like symbol tables that sometimes map multiple names to
   // the same physical function.
-  void AddVMRangeAllowAlias(uint64_t vmaddr, uint64_t size,
-                            const std::string& name);
+  void AddVMRangeAllowAlias(const char* analyzer, uint64_t vmaddr,
+                            uint64_t size, const std::string& name);
 
   // Like Add(), but allows that this addr/size might have previously been added
   // already under a different name.  If so, this add is simply ignored.
@@ -200,8 +203,8 @@
   // come from multiple source files.  But if it does, we don't want to alias
   // the entire source file to another, because it's probably only part of the
   // source file that overlaps.
-  void AddVMRangeIgnoreDuplicate(uint64_t vmaddr, uint64_t size,
-                                 const std::string& name);
+  void AddVMRangeIgnoreDuplicate(const char* analyzer, uint64_t vmaddr,
+                                 uint64_t size, const std::string& name);
 
   const DualMap& MapAtIndex(size_t index) const {
     return *outputs_[index].first;
diff --git a/src/disassemble.cc b/src/disassemble.cc
index 4b65876..f0a0365 100644
--- a/src/disassemble.cc
+++ b/src/disassemble.cc
@@ -80,7 +80,8 @@
           op->mem.index == X86_REG_INVALID) {
         uint64_t to_address = in->address + in->size + op->mem.disp;
         if (to_address) {
-          sink->AddVMRangeFor(in->address, to_address, RangeSink::kUnknownSize);
+          sink->AddVMRangeFor("x86_disassemble", in->address, to_address,
+                              RangeSink::kUnknownSize);
         }
       }
     }
diff --git a/src/dwarf.cc b/src/dwarf.cc
index 7e89a60..541277e 100644
--- a/src/dwarf.cc
+++ b/src/dwarf.cc
@@ -592,7 +592,7 @@
 
   void AddIndirectString(string_view range) const {
     if (strp_sink_) {
-      strp_sink_->AddFileRange(unit_name_, range);
+      strp_sink_->AddFileRange("dwarf_strp", unit_name_, range);
     }
   }
 
@@ -1851,8 +1851,8 @@
     std::string filename = map.GetFilename(ranges.debug_info_offset());
 
     while (ranges.NextRange()) {
-      sink->AddVMRangeIgnoreDuplicate(ranges.address(), ranges.length(),
-                                      filename);
+      sink->AddVMRangeIgnoreDuplicate("dwarf_aranges", ranges.address(),
+                                      ranges.length(), filename);
     }
   }
 
@@ -1876,7 +1876,7 @@
     if (high_pc > low_pc) {
       high_pc -= low_pc;
     }
-    sink->AddVMRangeIgnoreDuplicate(low_pc, high_pc, name);
+    sink->AddVMRangeIgnoreDuplicate("dwarf_pcpair", low_pc, high_pc, name);
   }
 
   // Sometimes a DIE has a linkage_name, which we can look up in the symbol
@@ -1884,8 +1884,8 @@
   if (attr.HasAttribute<1>()) {
     auto it = symtab.find(attr.GetAttribute<1>());
     if (it != symtab.end()) {
-      sink->AddVMRangeIgnoreDuplicate(it->second.first, it->second.second,
-                                      name);
+      sink->AddVMRangeIgnoreDuplicate("dwarf_linkagename", it->second.first,
+                                      it->second.second, name);
     }
   }
 
@@ -1910,7 +1910,7 @@
       // up in the symbol map.
       uint64_t size;
       if (symbol_map.vm_map.TryGetSize(addr, &size)) {
-        sink->AddVMRangeIgnoreDuplicate(addr, size, name);
+        sink->AddVMRangeIgnoreDuplicate("dwarf_location", addr, size, name);
       } else {
         if (verbose_level > 0) {
           fprintf(stderr,
@@ -1925,7 +1925,7 @@
   if (attr.HasAttribute<5>()) {
     absl::string_view loc_range = file.debug_loc.substr(attr.GetAttribute<5>());
     loc_range = GetLocationListRange(sizes, loc_range);
-    sink->AddFileRange(name, loc_range);
+    sink->AddFileRange("dwarf_locrange", name, loc_range);
   }
 
   uint64_t ranges_offset = UINT64_MAX;
@@ -1939,7 +1939,7 @@
   if (ranges_offset != UINT64_MAX) {
     absl::string_view ranges_range = file.debug_ranges.substr(ranges_offset);
     ranges_range = GetRangeListRange(sizes, ranges_range);
-    sink->AddFileRange(name, ranges_range);
+    sink->AddFileRange("dwarf_debugrange", name, ranges_range);
   }
 }
 
@@ -1965,7 +1965,7 @@
     attr_reader.ReadAttributes(&die_reader);
     std::string compileunit_name = std::string(attr_reader.GetAttribute<0>());
     if (!compileunit_name.empty()) {
-      sink->AddFileRange(compileunit_name, full_unit);
+      sink->AddFileRange("dwarf_pubnames", compileunit_name, full_unit);
     }
   }
 }
@@ -2078,6 +2078,7 @@
     uint8_t fde_encoding = 0;
     uint8_t lsda_encoding = 0;
     bool is_signal_handler = false;
+    bool has_augmentation_length = false;
     uint64_t personality_function = 0;
     uint32_t return_address_reg = 0;
   };
@@ -2115,6 +2116,7 @@
         switch (aug_string[0]) {
           case 'z':
             // Length until the end of augmentation data.
+            cie_info.has_augmentation_length = true;
             dwarf::ReadLEB128<uint32_t>(&entry);
             break;
           case 'L':
@@ -2148,9 +2150,23 @@
                                             nullptr, sink);
       // TODO(haberman); Technically the FDE addresses could span a
       // function/compilation unit?  They can certainly span inlines.
-      // uint64_t length =
-      //   ReadEncodedPointer(cie_info.fde_encoding & 0xf, true, &entry, sink);
-      sink->AddFileRangeFor(address, full_entry);
+      /*
+      uint64_t length =
+        ReadEncodedPointer(cie_info.fde_encoding & 0xf, true, &entry, sink);
+      (void)length;
+
+      if (cie_info.has_augmentation_length) {
+        uint32_t augmentation_length = dwarf::ReadLEB128<uint32_t>(&entry);
+        (void)augmentation_length;
+      }
+
+      uint64_t lsda =
+          ReadEncodedPointer(cie_info.lsda_encoding, true, &entry, sink);
+      if (lsda) {
+      }
+      */
+
+      sink->AddFileRangeFor("dwarf_fde", address, full_entry);
     }
   }
 }
@@ -2181,7 +2197,7 @@
         ReadEncodedPointer(table_enc, true, &data, base, sink);
     uint64_t fde_addr = ReadEncodedPointer(table_enc, true, &data, base, sink);
     entry_data.remove_suffix(data.size());
-    sink->AddFileRangeFor(initial_location, entry_data);
+    sink->AddFileRangeFor("dwarf_fde_table", initial_location, entry_data);
 
     // We could add fde_addr with an unknown length if we wanted to skip reading
     // eh_frame.  We can't count on this table being available though, so we
@@ -2199,7 +2215,7 @@
   data = sizes.ReadInitialLength(&data);
   data = data_with_length.substr(
       0, data.size() + (data.data() - data_with_length.data()));
-  sink->AddFileRange(unit_name, data);
+  sink->AddFileRange("dwarf_stmtlistrange", unit_name, data);
 }
 
 // The DWARF debug info can help us get compileunits info.  DIEs for compilation
@@ -2243,7 +2259,8 @@
     }
 
     die_reader.set_compileunit_name(compileunit_name);
-    sink->AddFileRange(compileunit_name, die_reader.unit_range());
+    sink->AddFileRange("dwarf_debuginfo", compileunit_name,
+                       die_reader.unit_range());
     AddDIE(file, compileunit_name, attr_reader, symtab, symbol_map,
            die_reader.unit_sizes(), sink);
 
@@ -2256,7 +2273,7 @@
     dwarf::SkipBytes(die_reader.debug_abbrev_offset(), &abbrev_data);
     dwarf::AbbrevTable unit_abbrev;
     abbrev_data = unit_abbrev.ReadAbbrevs(abbrev_data);
-    sink->AddFileRange(compileunit_name, abbrev_data);
+    sink->AddFileRange("dwarf_abbrev", compileunit_name, abbrev_data);
 
     while (die_reader.NextDIE()) {
       attr_reader.ReadAttributes(&die_reader);
@@ -2313,7 +2330,8 @@
       span_startaddr = addr;
     } else if (line_info.end_sequence ||
         (!last_source.empty() && name != last_source)) {
-      sink->AddVMRange(span_startaddr, addr - span_startaddr, last_source);
+      sink->AddVMRange("dwarf_stmtlist", span_startaddr, addr - span_startaddr,
+                       last_source);
       if (line_info.end_sequence) {
         span_startaddr = 0;
       } else {
diff --git a/src/elf.cc b/src/elf.cc
index 13075df..6c502da 100644
--- a/src/elf.cc
+++ b/src/elf.cc
@@ -720,9 +720,10 @@
   return true;
 }
 
-void MaybeAddFileRange(RangeSink* sink, string_view label, string_view range) {
+void MaybeAddFileRange(const char* analyzer, RangeSink* sink, string_view label,
+                       string_view range) {
   if (sink) {
-    sink->AddFileRange(label, range);
+    sink->AddFileRange(analyzer, label, range);
   }
 }
 
@@ -737,10 +738,10 @@
     ArFile::MemberFile member;
     ArFile::MemberReader reader(ar_file);
 
-    MaybeAddFileRange(sink, "[AR Headers]", ar_file.magic());
+    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
 
     while (reader.ReadMember(&member)) {
-      MaybeAddFileRange(sink, "[AR Headers]", member.header);
+      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
       switch (member.file_type) {
         case ArFile::MemberFile::kNormal: {
           ElfFile elf(member.contents);
@@ -748,16 +749,18 @@
             func(elf, member.filename, index_base);
             index_base += elf.section_count();
           } else {
-            MaybeAddFileRange(sink, "[AR Non-ELF Member File]",
+            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
                               member.contents);
           }
           break;
         }
         case ArFile::MemberFile::kSymbolTable:
-          MaybeAddFileRange(sink, "[AR Symbol Table]", member.contents);
+          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
+                            member.contents);
           break;
         case ArFile::MemberFile::kLongFilenameTable:
-          MaybeAddFileRange(sink, "[AR Headers]", member.contents);
+          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
+                            member.contents);
           break;
       }
     }
@@ -803,9 +806,64 @@
   }
 }
 
+static void ElfMachineToCapstone(Elf64_Half e_machine, cs_arch* arch,
+                                 cs_mode* mode) {
+  switch (e_machine) {
+    case EM_386:
+      *arch = CS_ARCH_X86;
+      *mode = CS_MODE_32;
+      break;
+    case EM_X86_64:
+      *arch = CS_ARCH_X86;
+      *mode = CS_MODE_64;
+      break;
+
+    // These aren't tested, but we include them on the off-chance
+    // that it will work.
+    case EM_ARM:
+      *arch = CS_ARCH_ARM;
+      *mode = CS_MODE_LITTLE_ENDIAN;
+      break;
+    case EM_MIPS:
+      *arch = CS_ARCH_MIPS;
+      break;
+    case EM_PPC:
+      *arch = CS_ARCH_PPC;
+      *mode = CS_MODE_32;
+      break;
+    case EM_PPC64:
+      *arch = CS_ARCH_PPC;
+      *mode = CS_MODE_64;
+      break;
+    case EM_SPARC:
+      *arch = CS_ARCH_SPARC;
+      *mode = CS_MODE_BIG_ENDIAN;
+      break;
+    case EM_SPARCV9:
+      *arch = CS_ARCH_SPARC;
+      *mode = CS_MODE_V9;
+      break;
+    default:
+      THROWF("Unknown ELF machine value: $0'", e_machine);
+  }
+}
+
+static void ReadElfArchMode(const InputFile& file, cs_arch* arch, cs_mode* mode) {
+  ForEachElf(file, nullptr,
+             [=](const ElfFile& elf, string_view /*filename*/,
+                 uint32_t /*index_base*/) {
+               // Last .o file wins?  (For .a files)?  It's kind of arbitrary,
+               // but a single .a file shouldn't have multiple archs in it.
+               ElfMachineToCapstone(elf.header().e_machine, arch, mode);
+             });
+}
+
 static void ReadELFSymbols(const InputFile& file, RangeSink* sink,
-                           SymbolTable* table) {
+                           SymbolTable* table, bool disassemble) {
   bool is_object = IsObjectFile(file.data());
+  DisassemblyInfo info;
+  DisassemblyInfo* infop = &info;
+  ReadElfArchMode(file, &info.arch, &info.mode);
 
   ForEachElf(
       file, sink,
@@ -849,15 +907,23 @@
             string_view name = strtab_section.ReadString(sym.st_name);
             uint64_t full_addr =
                 ToVMAddr(sym.st_value, index_base + sym.st_shndx, is_object);
-            if (sink) {
+            if (sink && !disassemble) {
               sink->AddVMRangeAllowAlias(
-                  full_addr, sym.st_size,
+                  "elf_symbols", full_addr, sym.st_size,
                   ItaniumDemangle(name, sink->data_source()));
             }
             if (table) {
               table->insert(
                   std::make_pair(name, std::make_pair(full_addr, sym.st_size)));
             }
+            if (disassemble && ELF64_ST_TYPE(sym.st_info) == STT_FUNC) {
+              if (verbose_level > 1) {
+                printf("Disassembling function: %s\n", name.data());
+              }
+              infop->text = sink->TranslateVMToFile(full_addr).substr(0, sym.st_size);
+              infop->start_address = full_addr;
+              DisassembleFindReferences(*infop, sink);
+            }
           }
         }
       });
@@ -893,8 +959,8 @@
         ToVMAddr(sym.st_value, index_base + sym.st_shndx, is_object);
     // Capture the trailing NULL.
     name = string_view(name.data(), name.size() + 1);
-    sink->AddFileRangeFor(full_addr, name);
-    sink->AddFileRangeFor(full_addr, sym_range);
+    sink->AddFileRangeFor("elf_symtab_name", full_addr, name);
+    sink->AddFileRangeFor("elf_symtab_sym", full_addr, sym_range);
   }
 }
 
@@ -909,7 +975,7 @@
     // TODO(haberman): fix this for object files.
     uint64_t full_addr = ToVMAddr(rela.r_offset, index_base, is_object);
     full_addr = rela.r_offset;
-    sink->AddFileRangeFor(full_addr, rela_range);
+    sink->AddFileRangeFor("elf_rela", full_addr, rela_range);
   }
 }
 
@@ -925,38 +991,7 @@
 
   // Disassemble first, because sometimes other tables will refer to things we
   // discovered through disassembling.
-  ForEachElf(
-      file, sink,
-      [&file, info, sink, is_object](const ElfFile& elf,
-                                     string_view /*filename*/,
-                                     uint32_t /*index_base*/) {
-        for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
-          ElfFile::Section section;
-          elf.ReadSection(i, &section);
-
-          if (section.header().sh_flags & SHF_EXECINSTR) {
-            // Use symbols to find functions in this executable section.
-            // Unfortunately we can't just disassemble the entire section
-            // because sometimes the padding between functions contains garbage
-            // (invalid instructions).
-            string_view filedata = file.data();
-            uint64_t offset = section.contents().data() - file.data().data();
-            uint64_t limit = offset + section.contents().size();
-            uint64_t vmbase = section.header().sh_addr - offset;
-            info->symbol_map.file_map.ForEachRangeWithStart(
-                offset, [limit, vmbase, filedata, info, sink](uint64_t start,
-                                                              uint64_t length) {
-                  if (start >= limit) {
-                    return false;
-                  }
-                  info->text = StrictSubstr(filedata, start, length);
-                  info->start_address = vmbase + start;
-                  DisassembleFindReferences(*info, sink);
-                  return true;
-                });
-          }
-        }
-      });
+  ReadELFSymbols(file, sink, nullptr, true);
 
   // Now scan other tables.
   ForEachElf(
@@ -1042,20 +1077,23 @@
             }
 
             name_from_flags += ']';
-            sink->AddRange(name_from_flags, full_addr, vmsize, contents);
+            sink->AddRange("elf_section", name_from_flags, full_addr, vmsize,
+                           contents);
           } else if (report_by == kReportBySectionName) {
-            sink->AddRange(name, full_addr, vmsize, contents);
+            sink->AddRange("elf_section", name, full_addr, vmsize, contents);
           } else if (report_by == kReportByEscapedSectionName) {
-            sink->AddRange(std::string("[section ") + std::string(name) + "]",
+            sink->AddRange("elf_section",
+                           std::string("[section ") + std::string(name) + "]",
                            full_addr, vmsize, contents);
           } else if (report_by == kReportByArchiveMember) {
-            sink->AddRange(filename, full_addr, vmsize, contents);
+            sink->AddRange("elf_section", filename, full_addr, vmsize,
+                           contents);
           }
         }
 
         if (report_by == kReportByArchiveMember) {
           // Cover unmapped parts of the file.
-          sink->AddFileRange(filename, elf.entire_file());
+          sink->AddFileRange("unmapped_armember", filename, elf.entire_file());
         }
       });
 }
@@ -1098,8 +1136,8 @@
                    name = absl::StrCat("[", name, "]");
                  }
 
-                 sink->AddRange(name, header.p_vaddr, header.p_memsz,
-                                segment.contents());
+                 sink->AddRange("elf_segment", name, header.p_vaddr,
+                                header.p_memsz, segment.contents());
                }
              });
 }
@@ -1154,73 +1192,23 @@
   }
 }
 
-static void ElfMachineToCapstone(Elf64_Half e_machine, cs_arch* arch,
-                                 cs_mode* mode) {
-  switch (e_machine) {
-    case EM_386:
-      *arch = CS_ARCH_X86;
-      *mode = CS_MODE_32;
-      break;
-    case EM_X86_64:
-      *arch = CS_ARCH_X86;
-      *mode = CS_MODE_64;
-      break;
-
-    // These aren't tested, but we include them on the off-chance
-    // that it will work.
-    case EM_ARM:
-      *arch = CS_ARCH_ARM;
-      *mode = CS_MODE_LITTLE_ENDIAN;
-      break;
-    case EM_MIPS:
-      *arch = CS_ARCH_MIPS;
-      break;
-    case EM_PPC:
-      *arch = CS_ARCH_PPC;
-      *mode = CS_MODE_32;
-      break;
-    case EM_PPC64:
-      *arch = CS_ARCH_PPC;
-      *mode = CS_MODE_64;
-      break;
-    case EM_SPARC:
-      *arch = CS_ARCH_SPARC;
-      *mode = CS_MODE_BIG_ENDIAN;
-      break;
-    case EM_SPARCV9:
-      *arch = CS_ARCH_SPARC;
-      *mode = CS_MODE_V9;
-      break;
-    default:
-      THROWF("Unknown ELF machine value: $0'", e_machine);
-  }
-}
-
-static void ReadElfArchMode(const InputFile& file, cs_arch* arch, cs_mode* mode) {
-  ForEachElf(file, nullptr,
-             [=](const ElfFile& elf, string_view /*filename*/,
-                 uint32_t /*index_base*/) {
-               // Last .o file wins?  (For .a files)?  It's kind of arbitrary,
-               // but a single .a file shouldn't have multiple archs in it.
-               ElfMachineToCapstone(elf.header().e_machine, arch, mode);
-             });
-}
-
 void AddCatchAll(RangeSink* sink) {
   ForEachElf(sink->input_file(), sink,
              [sink](const ElfFile& elf, string_view /*filename*/,
                     uint32_t /*index_base*/) {
-               sink->AddFileRange("[ELF Headers]", elf.header_region());
-               sink->AddFileRange("[ELF Headers]", elf.section_headers());
-               sink->AddFileRange("[ELF Headers]", elf.segment_headers());
-
+               sink->AddFileRange("elf_catchall", "[ELF Headers]",
+                                  elf.header_region());
+               sink->AddFileRange("elf_catchall", "[ELF Headers]",
+                                  elf.section_headers());
+               sink->AddFileRange("elf_catchall", "[ELF Headers]",
+                                  elf.segment_headers());
              });
 
   // The last-line fallback to make sure we cover the entire VM space.
   DoReadELFSegments(sink, kReportByEscapedSegmentName);
 
   // The last-line fallback to make sure we cover the entire file.
-  sink->AddFileRange("[Unmapped]", sink->input_file().data());
+  sink->AddFileRange("elf_catchall", "[Unmapped]", sink->input_file().data());
 }
 
 }  // namespace
@@ -1268,7 +1256,7 @@
         case DataSource::kRawSymbols:
         case DataSource::kShortSymbols:
         case DataSource::kFullSymbols:
-          ReadELFSymbols(debug_file().file_data(), sink, nullptr);
+          ReadELFSymbols(debug_file().file_data(), sink, nullptr, false);
           break;
         case DataSource::kArchiveMembers:
           DoReadELFSections(sink, kReportByArchiveMember);
@@ -1282,7 +1270,8 @@
                                 DataSource::kRawSymbols,
                                 &sinks[0]->MapAtIndex(0));
           symbol_sink.AddOutput(&symbol_map, &empty_munger);
-          ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symtab);
+          ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symtab,
+                         false);
           dwarf::File dwarf;
           ReadDWARFSections(debug_file().file_data(), &dwarf);
           ReadDWARFCompileUnits(dwarf, symtab, symbol_map, sink);
@@ -1347,7 +1336,8 @@
     SymbolTable symbol_table;
     RangeSink symbol_sink(&file_data(), symbol_source, &base_map);
     symbol_sink.AddOutput(&info->symbol_map, &empty_munger);
-    ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symbol_table);
+    ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symbol_table,
+                   false);
 
     if (symbol) {
       auto entry = symbol_table.find(*symbol);
diff --git a/src/macho.cc b/src/macho.cc
index 8c380c4..79c9758 100644
--- a/src/macho.cc
+++ b/src/macho.cc
@@ -106,7 +106,7 @@
 
   if (sink->data_source() == DataSource::kSegments) {
     sink->AddRange(
-        segname, segment->vmaddr, segment->vmsize,
+        "macho_segment", segname, segment->vmaddr, segment->vmsize,
         StrictSubstr(file_data, segment->fileoff, segment->filesize));
   } else if (sink->data_source() == DataSource::kSections) {
     uint32_t nsects = segment->nsects;
@@ -127,7 +127,7 @@
 
       std::string label = absl::StrJoin(
           std::make_tuple(segname, ArrayToStr(section->sectname, 16)), ",");
-      sink->AddRange(label, section->addr, section->size,
+      sink->AddRange("macho_section", label, section->addr, section->size,
                      StrictSubstr(file_data, section->offset, filesize));
     }
   } else {
@@ -139,18 +139,20 @@
                                RangeSink* sink) {
   auto info = GetStructPointer<dyld_info_command>(command_data);
 
-  sink->AddFileRange("Rebase Info", StrictSubstr(file_data, info->rebase_off,
-                                                 info->rebase_size));
-  sink->AddFileRange("Binding Info",
+  sink->AddFileRange(
+      "macho_dyld", "Rebase Info",
+      StrictSubstr(file_data, info->rebase_off, info->rebase_size));
+  sink->AddFileRange("macho_dyld", "Binding Info",
                      StrictSubstr(file_data, info->bind_off, info->bind_size));
   sink->AddFileRange(
-      "Weak Binding Info",
+      "macho_dyld", "Weak Binding Info",
       StrictSubstr(file_data, info->weak_bind_off, info->weak_bind_size));
   sink->AddFileRange(
-      "Lazy Binding Info",
+      "macho_dyld", "Lazy Binding Info",
       StrictSubstr(file_data, info->lazy_bind_off, info->lazy_bind_size));
-  sink->AddFileRange("Export Info", StrictSubstr(file_data, info->export_off,
-                                                 info->export_size));
+  sink->AddFileRange(
+      "macho_dyld", "Export Info",
+      StrictSubstr(file_data, info->export_off, info->export_size));
 }
 
 static void ParseSymbolTable(string_view command_data, string_view file_data,
@@ -158,10 +160,10 @@
   auto symtab = GetStructPointer<symtab_command>(command_data);
 
   // TODO(haberman): use 32-bit symbol size where appropriate.
-  sink->AddFileRange("Symbol Table",
+  sink->AddFileRange("macho_symtab", "Symbol Table",
                      StrictSubstr(file_data, symtab->symoff,
                                   symtab->nsyms * sizeof(nlist_64)));
-  sink->AddFileRange("String Table",
+  sink->AddFileRange("macho_symtab", "String Table",
                      StrictSubstr(file_data, symtab->stroff, symtab->strsize));
 }
 
@@ -170,24 +172,24 @@
   auto dysymtab = GetStructPointer<dysymtab_command>(command_data);
 
   sink->AddFileRange(
-      "Table of Contents",
+      "macho_dynsymtab", "Table of Contents",
       StrictSubstr(file_data, dysymtab->tocoff,
                    dysymtab->ntoc * sizeof(dylib_table_of_contents)));
-  sink->AddFileRange("Module Table",
+  sink->AddFileRange("macho_dynsymtab", "Module Table",
                      StrictSubstr(file_data, dysymtab->modtaboff,
                                   dysymtab->nmodtab * sizeof(dylib_module_64)));
   sink->AddFileRange(
-      "Referenced Symbol Table",
+      "macho_dynsymtab", "Referenced Symbol Table",
       StrictSubstr(file_data, dysymtab->extrefsymoff,
                    dysymtab->nextrefsyms * sizeof(dylib_reference)));
-  sink->AddFileRange("Indirect Symbol Table",
+  sink->AddFileRange("macho_dynsymtab", "Indirect Symbol Table",
                      StrictSubstr(file_data, dysymtab->indirectsymoff,
                                   dysymtab->nindirectsyms * sizeof(uint32_t)));
-  sink->AddFileRange("External Relocation Entries",
+  sink->AddFileRange("macho_dynsymtab", "External Relocation Entries",
                      StrictSubstr(file_data, dysymtab->extreloff,
                                   dysymtab->nextrel * sizeof(relocation_info)));
   sink->AddFileRange(
-      "Local Relocation Entries",
+      "macho_dynsymtab", "Local Relocation Entries",
       StrictSubstr(file_data, dysymtab->locreloff,
                    dysymtab->nlocrel * sizeof(struct relocation_info)));
 }
@@ -196,7 +198,8 @@
                                  string_view file_data, RangeSink* sink) {
   auto linkedit = GetStructPointer<linkedit_data_command>(command_data);
   sink->AddFileRange(
-      label, StrictSubstr(file_data, linkedit->dataoff, linkedit->datasize));
+      "macho_linkedit", label,
+      StrictSubstr(file_data, linkedit->dataoff, linkedit->datasize));
 }
 
 void ParseMachOLoadCommand(uint32_t cmd, string_view command_data,
@@ -275,7 +278,8 @@
         continue;
       }
 
-      sink->AddVMRange(addr, size, ItaniumDemangle(name, sink->data_source()));
+      sink->AddVMRange("macho_syms", addr, size,
+                       ItaniumDemangle(name, sink->data_source()));
     }
   }
 }
@@ -378,7 +382,7 @@
 }
 
 static void AddMachOFallback(RangeSink* sink) {
-  sink->AddFileRange("[Unmapped]", sink->input_file().data());
+  sink->AddFileRange("macho_fallback", "[Unmapped]", sink->input_file().data());
 }
 
 class MachOObjectFile : public ObjectFile {
diff --git a/src/range_map.h b/src/range_map.h
index 9c0058f..424a1ed 100644
--- a/src/range_map.h
+++ b/src/range_map.h
@@ -119,7 +119,8 @@
   template <class Func>
   void ForEachRangeWithStart(uint64_t start, Func func) const {
     for (auto iter = FindContaining(start); iter != mappings_.end(); ++iter) {
-      if (!func(iter->first, RangeEnd(iter) - iter->first)) {
+      if (!func(iter->second.label, iter->first,
+                RangeEnd(iter) - iter->first)) {
         return;
       }
     }
diff --git a/tests/range_map_test.cc b/tests/range_map_test.cc
index 732acaf..c88a6c8 100644
--- a/tests/range_map_test.cc
+++ b/tests/range_map_test.cc
@@ -344,6 +344,13 @@
   AssertMapEquals(map3_, {
     {125, UINT64_MAX, kNoTranslation, "translate me"}
   });
+
+  map2_.AddRange(20, 10, "fallback");
+
+  AssertRollupEquals({&map_, &map2_}, {
+    {{"foo", "fallback"}, 20, 25},
+    {{"foo", "translate me"}, 25, 30},
+  });
 }
 
 }  // namespace bloaty