diff --git a/src/developer/debug/debug_agent/BUILD.gn b/src/developer/debug/debug_agent/BUILD.gn
index 33152057bc8693767b8eb24dcdf95e693c9c00cd..eb40be2500f175dad04eb1564ea7667f3266a8ea 100644
--- a/src/developer/debug/debug_agent/BUILD.gn
+++ b/src/developer/debug/debug_agent/BUILD.gn
@@ -72,6 +72,10 @@ static_library("lib") {
     assert(false, "Un-supported CPU: ${current_cpu}")
   }
 
+  deps = [
+    "//src/lib/elflib",
+  ]
+
   public_deps = [
     "//garnet/lib/process",
     "//garnet/public/lib/svc/cpp",
diff --git a/src/developer/debug/debug_agent/process_info.cc b/src/developer/debug/debug_agent/process_info.cc
index 7a5afab5f93cf60b3d06c4234775aa5dbc94e502..e17e91e1abffd924628dc6a754223a49d25d6866 100644
--- a/src/developer/debug/debug_agent/process_info.cc
+++ b/src/developer/debug/debug_agent/process_info.cc
@@ -4,6 +4,9 @@
 
 #include "src/developer/debug/debug_agent/process_info.h"
 
+// Included early because of conflicts.
+#include "src/lib/elflib/elflib.h"
+
 #include <inttypes.h>
 #include <lib/zx/thread.h>
 #include <link.h>
@@ -16,7 +19,6 @@
 
 #include "src/developer/debug/debug_agent/arch.h"
 #include "src/developer/debug/debug_agent/object_util.h"
-#include "src/developer/debug/shared/elf.h"
 #include "src/lib/fxl/logging.h"
 
 namespace debug_agent {
@@ -142,7 +144,22 @@ zx_status_t GetModulesForProcess(const zx::process& process,
         if (ReadNullTerminatedString(process, str_addr, &module.name) != ZX_OK)
           return false;
 
-        module.build_id = debug_ipc::ExtractBuildID(process, module.base);
+        auto elf = elflib::ElfLib::Create(
+            [&process, base = module.base](uint64_t offset,
+                                           std::vector<uint8_t>* buf) {
+              size_t num_read = 0;
+
+              if (process.read_memory(base + offset, buf->data(), buf->size(),
+                                      &num_read) != ZX_OK) {
+                return false;
+              }
+
+              return num_read == buf->size();
+            });
+
+        if (elf) {
+          module.build_id = elf->GetGNUBuildID();
+        }
 
         modules->push_back(std::move(module));
         return true;
diff --git a/src/developer/debug/shared/BUILD.gn b/src/developer/debug/shared/BUILD.gn
index ba071e3aace4fe938746197ad3d96061cf1e2af9..ba071959ae19f5b52e8ba3961cb2789144bef1bf 100644
--- a/src/developer/debug/shared/BUILD.gn
+++ b/src/developer/debug/shared/BUILD.gn
@@ -12,8 +12,6 @@ static_library("shared") {
     "buffered_fd.h",
     "component_utils.cc",
     "component_utils.h",
-    "elf.cc",
-    "elf.h",
     "message_loop.cc",
     "message_loop.h",
     "regex.cc",
@@ -32,10 +30,6 @@ static_library("shared") {
     "//src/lib/fxl",
   ]
 
-  deps = [
-    "//src/lib/elflib",
-  ]
-
   if (current_toolchain == host_toolchain) {
     # Host toolchain.
     sources += [
@@ -64,45 +58,17 @@ static_library("shared") {
   }
 }
 
-if (current_toolchain == host_toolchain) {
-  # Copy the test file to the build directory, as elf_unittests will not be run
-  # near the source code.
-  copy("copy_test_file") {
-    # This file is a small valid ELF file for testing the parser with.
-    # It was generated by compiling the program:
-    #   int main() { return 1; }tests"
-    # on Linux with:
-    #   gcc -O2 file.c
-    sources = [
-      "testdata/small_test_file.elf",
-    ]
-    outputs = [
-      "$root_out_dir/test_data/debug_ipc/small_test_file.elf",
-    ]
-
-    metadata = {
-      test_runtime_deps = outputs
-    }
-  }
-}
-
 # Unit tests for this directory. These are intended to be referenced by unit
 # test targets for the consumers of this library.
 source_set("tests") {
   testonly = true
   sources = [
     "component_utils_unittest.cc",
-    "elf_unittest.cc",
     "message_loop_unittest.cc",
     "regex_unittest.cc",
     "stream_buffer_unittest.cc",
   ]
 
-  if (current_toolchain == host_toolchain) {
-    data_deps = [
-      ":copy_test_file",
-    ]
-  }
   deps = [
     ":shared",
     "//third_party/googletest:gtest",
diff --git a/src/developer/debug/shared/elf.cc b/src/developer/debug/shared/elf.cc
deleted file mode 100644
index bac35d239a9230ff623c880ed8c87dac23d6978d..0000000000000000000000000000000000000000
--- a/src/developer/debug/shared/elf.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/developer/debug/shared/elf.h"
-
-#include "src/lib/elflib/elflib.h"
-
-namespace debug_ipc {
-
-namespace {
-
-constexpr size_t kMaxBuildIDSize = 64;
-
-constexpr uint64_t kNoteGnuBuildId = 3;
-
-}  // namespace
-
-using elflib::Elf64_Ehdr;
-using elflib::Elf64_Phdr;
-using elflib::Elf64_Shdr;
-using elflib::ElfLib;
-
-std::string ExtractBuildID(
-    std::function<bool(uint64_t offset, void* buffer, size_t length)> read_fn) {
-  // The buffer will hold a hex version of the build ID (2 chars per byte)
-  // plus the null terminator (1 more).
-  constexpr size_t buf_size = kMaxBuildIDSize * 2 + 1;
-  char buf[buf_size];
-
-  auto elf =
-      ElfLib::Create([read_fn](uint64_t offset, std::vector<uint8_t>* buf) {
-        return read_fn(offset, buf->data(), buf->size());
-      });
-
-  if (!elf) {
-    return std::string();
-  }
-
-  auto note = elf->GetNote("GNU", kNoteGnuBuildId);
-
-  if (note && note->size() <= kMaxBuildIDSize) {
-    size_t i = 0;
-    for (const auto& c : *note)
-      snprintf(&buf[i++ * 2], 3, "%02x", c);
-    return std::string(buf);
-  }
-
-  return std::string();
-}
-
-std::string ExtractBuildID(FILE* file) {
-  return ExtractBuildID([file](uint64_t offset, void* buffer, size_t length) {
-    if (fseek(file, offset, SEEK_SET) != 0)
-      return false;
-    return fread(buffer, 1, length, file) == length;
-  });
-}
-
-#if defined(__Fuchsia__)
-std::string ExtractBuildID(const zx::process& process, uint64_t base) {
-  return ExtractBuildID([&process, base](uint64_t offset, void* buffer,
-                                         size_t length) {
-    size_t num_read = 0;
-    if (process.read_memory(base + offset, buffer, length, &num_read) != ZX_OK)
-      return false;
-    return num_read == length;
-  });
-}
-#endif
-
-}  // namespace debug_ipc
diff --git a/src/developer/debug/shared/elf.h b/src/developer/debug/shared/elf.h
deleted file mode 100644
index 5ede475d2493fdc847e8d2f06ae67c443fc2abc8..0000000000000000000000000000000000000000
--- a/src/developer/debug/shared/elf.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <stdint.h>
-#include <stdio.h>
-
-#include <functional>
-#include <string>
-
-#if defined(__Fuchsia__)
-#include <lib/zx/process.h>
-#endif
-
-namespace debug_ipc {
-
-// Extracts the build ID from some ELF data. Returns the empty string on
-// failure.
-//
-// The parameter is a function that that implements an fread-like interface to
-// read from the ELF data. This allows the extractor to handle in-memory and
-// on-disk version. It returns true on success, false on failure (failures
-// include all partial reads). The offset is relative to the beginning of the
-// ELF file.
-std::string ExtractBuildID(
-    std::function<bool(uint64_t offset, void* buffer, size_t length)> read_fn);
-
-// This variant extracts the build ID from the given file.
-std::string ExtractBuildID(FILE* file);
-
-#if defined(__Fuchsia__)
-// This variant extracts the build ID from an ELF file mapped into memory for
-// the given process at the given location.
-std::string ExtractBuildID(const zx::process& process, uint64_t base);
-#endif
-
-}  // namespace debug_ipc
diff --git a/src/developer/debug/shared/elf_unittest.cc b/src/developer/debug/shared/elf_unittest.cc
deleted file mode 100644
index ddff82de9d4db04e6acee892048909a22a6caeb9..0000000000000000000000000000000000000000
--- a/src/developer/debug/shared/elf_unittest.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/developer/debug/shared/elf.h"
-#include "gtest/gtest.h"
-
-#include <unistd.h>
-
-#if defined(__APPLE__)
-#include <mach-o/dyld.h>
-#endif
-
-namespace debug_ipc {
-
-#if !defined(__Fuchsia__)
-// This test requires a test data file which has not been set up for packaging
-// on Fuchsia yet.
-// TODO(brettw) set this up and enable this test on Fuchsia.
-
-namespace {
-
-std::string GetSelfPath() {
-  std::string result;
-#if defined(__APPLE__)
-  // Executable path can have relative references ("..") depending on how the
-  // app was launched.
-  uint32_t length = 0;
-  _NSGetExecutablePath(nullptr, &length);
-  result.resize(length);
-  _NSGetExecutablePath(&result[0], &length);
-  result.resize(length - 1);  // Length included terminator.
-#elif defined(__linux__)
-  // The realpath() call below will resolve the symbolic link.
-  result.assign("/proc/self/exe");
-#else
-#error Write this for your platform.
-#endif
-
-  char fullpath[PATH_MAX];
-  return std::string(realpath(result.c_str(), fullpath));
-}
-
-std::string GetSmallTestElfFileName() {
-  std::string path = GetSelfPath();
-  size_t last_slash = path.rfind('/');
-  if (last_slash == std::string::npos) {
-    path = "./";  // Just hope the current directory works.
-  } else {
-    path.resize(last_slash + 1);
-  }
-  path += "test_data/debug_ipc/small_test_file.elf";
-  return path;
-}
-
-}  // namespace
-
-TEST(Elf, ExtractBuildID) {
-  std::string small_test_file_name = GetSmallTestElfFileName();
-
-  FILE* small_test_file = fopen(small_test_file_name.c_str(), "rb");
-  ASSERT_TRUE(small_test_file) << small_test_file_name.c_str();
-  std::string build_id = ExtractBuildID(small_test_file);
-  fclose(small_test_file);
-
-  // This expected build ID was extracted with:
-  //   eu-readelf -n small_test_file.elf
-  EXPECT_EQ("763feb38b0e37a89964c330c5cf7f7af2ce79e54", build_id);
-}
-#endif
-
-}  // namespace debug_ipc
diff --git a/src/developer/debug/zxdb/symbols/BUILD.gn b/src/developer/debug/zxdb/symbols/BUILD.gn
index 942c3c0104281a20b2902fd22d33eb013bac5222..eb8f1d6af7040a1b20d9e41ad61c6a6f3e7608a1 100644
--- a/src/developer/debug/zxdb/symbols/BUILD.gn
+++ b/src/developer/debug/zxdb/symbols/BUILD.gn
@@ -172,6 +172,26 @@ copy("copy_test_so") {
   ]
 }
 
+if (current_toolchain == host_toolchain) {
+  copy("copy_test_elf_file") {
+    # This file is a small valid ELF file for testing the parser with.
+    # It was generated by compiling the program:
+    #   int main() { return 1; }
+    # on Linux with:
+    #   gcc -O2 file.c
+    sources = [
+      "test_data/small_test_file.elf",
+    ]
+    outputs = [
+      "$root_out_dir/test_data/zxdb/small_test_file.elf",
+    ]
+
+    metadata = {
+      test_runtime_deps = outputs
+    }
+  }
+}
+
 source_set("tests") {
   testonly = true
 
@@ -202,10 +222,10 @@ source_set("tests") {
   ]
 
   deps = [
+    ":copy_test_elf_file($host_toolchain)",
     ":symbols",
     ":test_support",
     "//garnet/third_party/llvm:LLVMDebugInfoDWARF",
-    "//src/developer/debug/shared:copy_test_file($host_toolchain)",
     "//src/developer/debug/zxdb/common:test_support",
     "//third_party/googletest:gtest",
   ]
diff --git a/src/developer/debug/zxdb/symbols/build_id_index.cc b/src/developer/debug/zxdb/symbols/build_id_index.cc
index 03cec272544ea8667aa597a7fe5199b7c99444bb..740abadf496248ae2261c678fd345cfd5e634c27 100644
--- a/src/developer/debug/zxdb/symbols/build_id_index.cc
+++ b/src/developer/debug/zxdb/symbols/build_id_index.cc
@@ -6,8 +6,8 @@
 
 #include <algorithm>
 
-#include "src/developer/debug/shared/elf.h"
 #include "src/developer/debug/zxdb/common/string_util.h"
+#include "src/lib/elflib/elflib.h"
 #include "src/lib/fxl/strings/string_printf.h"
 #include "src/lib/fxl/strings/string_view.h"
 #include "src/lib/fxl/strings/trim.h"
@@ -242,12 +242,11 @@ void BuildIDIndex::IndexOneSourcePath(const std::string& path) {
 }
 
 bool BuildIDIndex::IndexOneSourceFile(const std::string& file_path) {
-  FILE* file = fopen(file_path.c_str(), "rb");
-  if (!file)
+  auto elf = elflib::ElfLib::Create(file_path);
+  if (!elf)
     return false;
-  std::string build_id = debug_ipc::ExtractBuildID(file);
-  fclose(file);
 
+  std::string build_id = elf->GetGNUBuildID();
   if (!build_id.empty()) {
     build_id_to_file_[build_id] = file_path;
     return true;
diff --git a/src/developer/debug/zxdb/symbols/build_id_index_unittest.cc b/src/developer/debug/zxdb/symbols/build_id_index_unittest.cc
index 67b81797db60e4daff6525bb7cf9ba1f93a993cf..017f5390077c8faa741f6160cd1d779707f6cb0b 100644
--- a/src/developer/debug/zxdb/symbols/build_id_index_unittest.cc
+++ b/src/developer/debug/zxdb/symbols/build_id_index_unittest.cc
@@ -18,7 +18,7 @@ const char kSmallTestBuildID[] = "763feb38b0e37a89964c330c5cf7f7af2ce79e54";
 std::filesystem::path GetTestDataDir() {
   std::filesystem::path path(GetSelfPath());
   path.remove_filename();
-  path.append("test_data/debug_ipc/");
+  path.append("test_data/zxdb/");
   return path;
 }
 
diff --git a/src/developer/debug/shared/testdata/small_test_file.elf b/src/developer/debug/zxdb/symbols/test_data/small_test_file.elf
similarity index 100%
rename from src/developer/debug/shared/testdata/small_test_file.elf
rename to src/developer/debug/zxdb/symbols/test_data/small_test_file.elf
diff --git a/src/lib/elflib/elflib.cc b/src/lib/elflib/elflib.cc
index 472927c627e8430e6479de515112663c78f19319..d2512e13fabd1d506eedef213007db344bb773a5 100644
--- a/src/lib/elflib/elflib.cc
+++ b/src/lib/elflib/elflib.cc
@@ -12,6 +12,9 @@
 namespace elflib {
 namespace {
 
+// NT_GNU_BUILD_ID identifier.
+constexpr uint64_t kNoteGnuBuildId = 3;
+
 // Pull a null-terminated string out of an array of bytes at an offset. Returns
 // empty string if there is no null terminator.
 std::string GetNullTerminatedStringAt(const uint8_t* data, size_t data_length,
@@ -442,6 +445,23 @@ std::optional<std::vector<uint8_t>> ElfLib::GetNote(const std::string& name,
   return std::nullopt;
 }
 
+std::string ElfLib::GetGNUBuildID() {
+  auto note = GetNote("GNU", kNoteGnuBuildId);
+  if (!note) {
+    return std::string();
+  }
+
+  std::string ret;
+
+  for (const auto& byte : *note) {
+    char buf[3];
+    snprintf(buf, 3, "%02x", byte);
+    ret += buf;
+  }
+
+  return ret;
+}
+
 ElfLib::MemoryRegion ElfLib::GetSectionData(size_t section) {
   const Elf64_Shdr* header = GetSectionHeader(section);
 
diff --git a/src/lib/elflib/elflib.h b/src/lib/elflib/elflib.h
index 011c6c08eff04c133284270ff8659b7b705f854e..508cda54f1bbd5e73779ec971158163177a72951 100644
--- a/src/lib/elflib/elflib.h
+++ b/src/lib/elflib/elflib.h
@@ -67,6 +67,10 @@ class ElfLib {
   std::optional<std::vector<uint8_t>> GetNote(const std::string& name,
                                               uint64_t type);
 
+  // Get the NT_GNU_BUILD_ID note as a hex string. Return empty string if we
+  // don't have that note.
+  std::string GetGNUBuildID();
+
   // Get a symbol from the symbol table. Return nullptr if there is no such
   // symbol. Pointer should live as long as the memory accessor.
   const Elf64_Sym* GetSymbol(const std::string& name);
diff --git a/src/lib/elflib/elflib_unittest.cc b/src/lib/elflib/elflib_unittest.cc
index a147e527f1523492426a031182c0e85318fef808..ea1783a7c26e4914c5083a7f15420b219e702e46 100644
--- a/src/lib/elflib/elflib_unittest.cc
+++ b/src/lib/elflib/elflib_unittest.cc
@@ -283,6 +283,9 @@ TEST(ElfLib, GetNote) {
   for (size_t i = 0; i < 32; i++) {
     EXPECT_EQ(i % 8, data[i]);
   }
+
+  EXPECT_EQ("0001020304050607000102030405060700010203040506070001020304050607",
+            elf->GetGNUBuildID());
 }
 
 TEST(ElfLib, MissingSections) {