Fixed a few bugs with total file size, and added tests to verify.

With separate debug files, parts of the debug file were getting
counted.

There were some bugs where the total file sizes was not correct.
diff --git a/src/bloaty.cc b/src/bloaty.cc
index 3d4fd37..fa3ba4f 100644
--- a/src/bloaty.cc
+++ b/src/bloaty.cc
@@ -372,6 +372,8 @@
     }
   }
 
+  int64_t file_total() const { return file_total_; }
+
  private:
   BLOATY_DISALLOW_COPY_AND_ASSIGN(Rollup);
 
@@ -1134,6 +1136,8 @@
       pair.first->file_map.AddRangeWithTranslation(fileoff, filesize, label,
                                                     translator_->file_map,
                                                     &pair.first->vm_map);
+    } else {
+      pair.first->file_map.AddRange(fileoff, filesize, label);
     }
   }
 }
@@ -1513,10 +1517,6 @@
     sink_ptrs.push_back(sinks.back().get());
   }
 
-  // Ensure all parts of the VM/file-space are covered.  If all data sources had
-  // 100% coverage, this wouldn't be necessary.
-  maps.base_map()->file_map.AddRange(0, file->file_data().data().size(),
-                                     "[None]");
   std::string build_id = file->GetBuildId();
   if (!build_id.empty()) {
     auto iter = debug_files_.find(build_id);
@@ -1525,9 +1525,16 @@
       *out_build_id = build_id;
     }
   }
-  file->ProcessFile(sink_ptrs);
 
+  int64_t filesize_before = rollup->file_total();
+  file->ProcessFile(sink_ptrs);
   maps.ComputeRollup(filename, filename_position_, rollup);
+
+  // The ObjectFile implementation must guarantee this.
+  int64_t filesize = rollup->file_total() - filesize_before;
+  (void)filesize;
+  assert(filesize == file->file_data().data().size());
+
   if (verbose_level > 0) {
     fprintf(stderr, "FILE MAP:\n");
     maps.PrintFileMaps(filename, filename_position_);
diff --git a/src/elf.cc b/src/elf.cc
index 4a575a5..08598d3 100644
--- a/src/elf.cc
+++ b/src/elf.cc
@@ -708,24 +708,6 @@
 }
 
 template <class Func>
-void OnElfFile(const ElfFile& elf, string_view filename,
-               unsigned long index_base, RangeSink* sink, Func func) {
-  func(elf, filename, index_base);
-
-  // Add these *after* running the user callback.  That way if there is
-  // overlap, the user's annotations will take precedence.
-  MaybeAddFileRange(sink, "[ELF Headers]", elf.header_region());
-  MaybeAddFileRange(sink, "[ELF Headers]", elf.section_headers());
-  MaybeAddFileRange(sink, "[ELF Headers]", elf.segment_headers());
-
-  // Any sections of the file not covered by any segments/sections/symbols/etc.
-  if (sink && (sink->data_source() == DataSource::kSegments ||
-               sink->data_source() == DataSource::kSections)) {
-    sink->AddFileRange("[Unmapped]", elf.entire_file());
-  }
-}
-
-template <class Func>
 bool ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
   ArFile ar_file(file.data());
   unsigned long index_base = 0;
@@ -742,7 +724,7 @@
         case ArFile::MemberFile::kNormal: {
           ElfFile elf(member.contents);
           if (elf.IsOpen()) {
-            OnElfFile(elf, member.filename, index_base, sink, func);
+            func(elf, member.filename, index_base);
             index_base += elf.section_count();
           } else {
             MaybeAddFileRange(sink, "[AR Non-ELF Member File]",
@@ -766,20 +748,24 @@
       return false;
     }
 
-    OnElfFile(elf, file.filename(), index_base, sink, func);
+    func(elf, file.filename(), index_base);
   }
 
   return true;
 }
 
+void AddELFFallback(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());
 
-// There are several programs that offer useful information about
-// binaries:
-//
-// - objdump: display object file headers and contents (including disassembly)
-// - readelf: more ELF-specific objdump (no disassembly though)
-// - nm: display symbols
-// - size: display binary size
+             });
+  // The last-line fallback to make sure we cover the entire file.
+  sink->AddFileRange("[Unmapped]", sink->input_file().data());
+}
 
 // For object files, addresses are relative to the section they live in, which
 // is indicated by ndx.  We split this into:
@@ -1127,6 +1113,7 @@
         default:
           THROW("unknown data source");
       }
+      AddELFFallback(sink);
     }
   }
 
diff --git a/src/macho.cc b/src/macho.cc
index ac5dd1e..8c380c4 100644
--- a/src/macho.cc
+++ b/src/macho.cc
@@ -377,6 +377,10 @@
   }
 }
 
+static void AddMachOFallback(RangeSink* sink) {
+  sink->AddFileRange("[Unmapped]", sink->input_file().data());
+}
+
 class MachOObjectFile : public ObjectFile {
  public:
   MachOObjectFile(std::unique_ptr<InputFile> file_data)
@@ -404,6 +408,7 @@
         default:
           THROW("Mach-O doesn't support this data source");
       }
+      AddMachOFallback(sink);
     }
   }
 
diff --git a/tests/bloaty_test.cc b/tests/bloaty_test.cc
index e7f370a..006c03c 100644
--- a/tests/bloaty_test.cc
+++ b/tests/bloaty_test.cc
@@ -254,3 +254,8 @@
     std::make_tuple("foo_y", 4, 0)
   });
 }
+
+TEST_F(BloatyTest, SeparateDebug) {
+  RunBloaty({"bloaty", "--debug-file=05-binary.bin", "07-binary-stripped.bin",
+             "-d", "symbols"});
+}
diff --git a/tests/test.h b/tests/test.h
index dfc5231..0e68579 100644
--- a/tests/test.h
+++ b/tests/test.h
@@ -128,6 +128,17 @@
 
   void CheckConsistency(const bloaty::Options& options) {
     ASSERT_EQ(options.base_filename_size() > 0, output_->diff_mode());
+
+    if (!output_->diff_mode()) {
+      size_t total_input_size = 0;
+      for (const auto& filename : options.filename()) {
+        uint64_t size;
+        ASSERT_TRUE(GetFileSize(filename, &size));
+        total_input_size += size;
+      }
+      ASSERT_EQ(top_row_->filesize, total_input_size);
+    }
+
     int rows = 0;
     CheckConsistencyForRow(*top_row_, true, output_->diff_mode(), &rows);
     CheckCSVConsistency(rows);
diff --git a/tests/testdata/linux-x86/07-binary-stripped.bin b/tests/testdata/linux-x86/07-binary-stripped.bin
new file mode 100644
index 0000000..9bcbe46
--- /dev/null
+++ b/tests/testdata/linux-x86/07-binary-stripped.bin
Binary files differ
diff --git a/tests/testdata/linux-x86_64/07-binary-stripped.bin b/tests/testdata/linux-x86_64/07-binary-stripped.bin
new file mode 100644
index 0000000..0035670
--- /dev/null
+++ b/tests/testdata/linux-x86_64/07-binary-stripped.bin
Binary files differ
diff --git a/tests/testdata/make_test_files.sh b/tests/testdata/make_test_files.sh
index 85ea950..bb75402 100755
--- a/tests/testdata/make_test_files.sh
+++ b/tests/testdata/make_test_files.sh
@@ -114,3 +114,7 @@
 "
 
 make_ar "06-diff.a" "foo2.o" "bar.o" "a_filename_longer_than_sixteen_chars.o"
+
+cp "05-binary.bin" "07-binary-stripped.bin"
+strip "07-binary-stripped.bin"
+publish "07-binary-stripped.bin"