[debugger] Attach ELF symbols to LoadedModuleSymbols

Test: Unit tests pass
Change-Id: Ie5181d88967c2da5eafdcf2f93bcb5b063aa0630
diff --git a/bin/zxdb/client/breakpoint_impl_unittest.cc b/bin/zxdb/client/breakpoint_impl_unittest.cc
index a293339..1292ac9 100644
--- a/bin/zxdb/client/breakpoint_impl_unittest.cc
+++ b/bin/zxdb/client/breakpoint_impl_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "garnet/bin/zxdb/client/breakpoint_impl.h"
 #include "garnet/bin/zxdb/client/process_impl.h"
+#include "garnet/bin/zxdb/client/process_observer.h"
 #include "garnet/bin/zxdb/client/remote_api_test.h"
 #include "garnet/bin/zxdb/client/session.h"
 #include "garnet/bin/zxdb/client/target_impl.h"
@@ -49,10 +50,24 @@
         FROM_HERE, [cb]() { cb(Err(), debug_ipc::RemoveBreakpointReply()); });
   }
 
+  void SymbolTables(
+      const debug_ipc::SymbolTablesRequest& request,
+      std::function<void(const Err&, debug_ipc::SymbolTablesReply)> cb)
+      override {
+    MessageLoop::Current()->PostTask(
+        FROM_HERE, [cb]() { cb(Err(), debug_ipc::SymbolTablesReply()); });
+  }
+
   std::vector<AddPair> adds;
   std::vector<RemovePair> removes;
 };
 
+class StopOnLoadModuleObserver : public ProcessObserver {
+  void DidLoadModuleSymbols(Process* process, LoadedModuleSymbols* module) {
+    MessageLoop::Current()->QuitNow();
+  }
+};
+
 class BreakpointImplTest : public RemoteAPITest {
  public:
   BreakpointImplTest() = default;
@@ -148,6 +163,10 @@
   modules.push_back(load1);
   target->process()->OnModules(modules, std::vector<uint64_t>());
 
+  StopOnLoadModuleObserver observer;
+  target->process()->AddObserver(&observer);
+  MessageLoop::Current()->Run();
+
   // That should have notified the breakpoint which should have added the two
   // addresses to the backend.
   ASSERT_FALSE(sink().adds.empty());
diff --git a/bin/zxdb/client/mock_remote_api.cc b/bin/zxdb/client/mock_remote_api.cc
index c875551..ab647ac 100644
--- a/bin/zxdb/client/mock_remote_api.cc
+++ b/bin/zxdb/client/mock_remote_api.cc
@@ -35,7 +35,7 @@
     std::function<void(const Err&, debug_ipc::ThreadStatusReply)> cb) {
   // Returns the canned response.
   debug_ipc::MessageLoop::Current()->PostTask(
-      FROM_HERE, [ cb, response = thread_status_reply_ ]() {
+      FROM_HERE, [cb, response = thread_status_reply_]() {
         cb(Err(), std::move(response));
       });
 }
@@ -63,4 +63,11 @@
   });
 }
 
+void MockRemoteAPI::SymbolTables(
+    const debug_ipc::SymbolTablesRequest& request,
+    std::function<void(const Err&, debug_ipc::SymbolTablesReply)> cb) {
+  debug_ipc::MessageLoop::Current()->PostTask(
+      FROM_HERE, [cb]() { cb(Err(), debug_ipc::SymbolTablesReply()); });
+}
+
 }  // namespace zxdb
diff --git a/bin/zxdb/client/mock_remote_api.h b/bin/zxdb/client/mock_remote_api.h
index bea8a85..6c29409 100644
--- a/bin/zxdb/client/mock_remote_api.h
+++ b/bin/zxdb/client/mock_remote_api.h
@@ -67,6 +67,10 @@
       const debug_ipc::WriteRegistersRequest& request,
       std::function<void(const Err&, debug_ipc::WriteRegistersReply)> cb)
       override;
+  void SymbolTables(
+      const debug_ipc::SymbolTablesRequest& request,
+      std::function<void(const Err&, debug_ipc::SymbolTablesReply)> cb)
+      override;
 
  private:
   debug_ipc::ThreadStatusReply thread_status_reply_;
diff --git a/bin/zxdb/client/process_impl.cc b/bin/zxdb/client/process_impl.cc
index 769e26a..5e2fea4 100644
--- a/bin/zxdb/client/process_impl.cc
+++ b/bin/zxdb/client/process_impl.cc
@@ -14,6 +14,7 @@
 #include "garnet/bin/zxdb/client/target_impl.h"
 #include "garnet/bin/zxdb/client/thread_impl.h"
 #include "garnet/bin/zxdb/symbols/input_location.h"
+#include "garnet/bin/zxdb/symbols/loaded_module_symbols.h"
 #include "garnet/public/lib/fxl/logging.h"
 
 namespace zxdb {
@@ -55,7 +56,7 @@
   debug_ipc::ModulesRequest request;
   request.process_koid = koid_;
   session()->remote_api()->Modules(
-      request, [ process = weak_factory_.GetWeakPtr(), callback ](
+      request, [process = weak_factory_.GetWeakPtr(), callback](
                    const Err& err, debug_ipc::ModulesReply reply) {
         if (process)
           process->symbols_.SetModules(reply.modules);
@@ -94,7 +95,7 @@
   debug_ipc::ThreadsRequest request;
   request.process_koid = koid_;
   session()->remote_api()->Threads(
-      request, [ callback, process = weak_factory_.GetWeakPtr() ](
+      request, [callback, process = weak_factory_.GetWeakPtr()](
                    const Err& err, debug_ipc::ThreadsReply reply) {
         if (process) {
           process->UpdateThreads(reply.threads);
@@ -241,8 +242,22 @@
 }
 
 void ProcessImpl::DidLoadModuleSymbols(LoadedModuleSymbols* module) {
-  for (auto& observer : observers())
-    observer.DidLoadModuleSymbols(this, module);
+  debug_ipc::SymbolTablesRequest request;
+
+  request.process_koid = koid_;
+  request.base = module->load_address();
+  request.build_id = module->build_id();
+
+  session()->remote_api()->SymbolTables(
+      request,
+      [this, module](const Err& err, debug_ipc::SymbolTablesReply reply) {
+        if (!err.has_error()) {
+          module->SetElfSymbols(reply.symbols);
+        }
+
+        for (auto& observer : observers())
+          observer.DidLoadModuleSymbols(this, module);
+      });
 }
 
 void ProcessImpl::WillUnloadModuleSymbols(LoadedModuleSymbols* module) {
diff --git a/bin/zxdb/client/thread_controller_test.cc b/bin/zxdb/client/thread_controller_test.cc
index b8f6a6d..94be9e3 100644
--- a/bin/zxdb/client/thread_controller_test.cc
+++ b/bin/zxdb/client/thread_controller_test.cc
@@ -5,6 +5,7 @@
 #include "garnet/bin/zxdb/client/thread_controller_test.h"
 
 #include "garnet/bin/zxdb/client/process_impl.h"
+#include "garnet/bin/zxdb/client/process_observer.h"
 #include "garnet/bin/zxdb/client/session.h"
 #include "garnet/bin/zxdb/client/system.h"
 #include "garnet/bin/zxdb/client/target_impl.h"
@@ -13,6 +14,12 @@
 
 namespace zxdb {
 
+class StopOnLoadModuleObserver : public ProcessObserver {
+  void DidLoadModuleSymbols(Process* process, LoadedModuleSymbols* module) {
+    debug_ipc::MessageLoop::Current()->QuitNow();
+  }
+};
+
 // static
 const uint64_t ThreadControllerTest::kUnsymbolizedModuleAddress = 0x4000000;
 
@@ -51,6 +58,11 @@
 
   TargetImpl* target = session().system_impl().GetTargetImpls()[0];
   target->process()->OnModules(modules, std::vector<uint64_t>());
+
+  StopOnLoadModuleObserver observer;
+  target->process()->AddObserver(&observer);
+  debug_ipc::MessageLoop::Current()->Run();
+  target->process()->RemoveObserver(&observer);
 }
 
 std::unique_ptr<RemoteAPI> ThreadControllerTest::GetRemoteAPIImpl() {
diff --git a/bin/zxdb/symbols/loaded_module_symbols.cc b/bin/zxdb/symbols/loaded_module_symbols.cc
index 40b058c..6155dfa 100644
--- a/bin/zxdb/symbols/loaded_module_symbols.cc
+++ b/bin/zxdb/symbols/loaded_module_symbols.cc
@@ -8,9 +8,11 @@
 namespace zxdb {
 
 LoadedModuleSymbols::LoadedModuleSymbols(
-    fxl::RefPtr<SystemSymbols::ModuleRef> module, uint64_t load_address)
+    fxl::RefPtr<SystemSymbols::ModuleRef> module, std::string build_id,
+    uint64_t load_address)
     : module_(std::move(module)),
       load_address_(load_address),
+      build_id_(std::move(build_id)),
       symbol_context_(load_address) {}
 
 LoadedModuleSymbols::~LoadedModuleSymbols() = default;
diff --git a/bin/zxdb/symbols/loaded_module_symbols.h b/bin/zxdb/symbols/loaded_module_symbols.h
index ffe102f..69f44f6 100644
--- a/bin/zxdb/symbols/loaded_module_symbols.h
+++ b/bin/zxdb/symbols/loaded_module_symbols.h
@@ -12,6 +12,7 @@
 #include "garnet/bin/zxdb/symbols/location.h"
 #include "garnet/bin/zxdb/symbols/resolve_options.h"
 #include "garnet/bin/zxdb/symbols/system_symbols.h"
+#include "garnet/lib/debug_ipc/records.h"
 #include "garnet/public/lib/fxl/macros.h"
 
 namespace zxdb {
@@ -25,7 +26,7 @@
 class LoadedModuleSymbols {
  public:
   LoadedModuleSymbols(fxl::RefPtr<SystemSymbols::ModuleRef> module,
-                      uint64_t load_address);
+                      std::string build_id, uint64_t load_address);
   ~LoadedModuleSymbols();
 
   // Returns the underlying ModuleSymbols object.
@@ -37,10 +38,23 @@
   // Base address for the module.
   uint64_t load_address() const { return load_address_; }
 
+  // Build ID for the module.
+  const std::string& build_id() const { return build_id_; }
+
+  // ELF Symbols for the module.
+  const std::vector<debug_ipc::ElfSymbol>& elf_symbols() const {
+    return elf_symbols_;
+  }
+
   // Most functions in ModuleSymbols take a symbol context to convert between
   // absolute addresses in memory to ones relative to the module load address.
   const SymbolContext& symbol_context() const { return symbol_context_; }
 
+  // Set the elf symbols for the module.
+  void SetElfSymbols(std::vector<debug_ipc::ElfSymbol> symbols) {
+    elf_symbols_ = std::move(symbols);
+  }
+
   // Converts the given InputLocation into one or more locations. If the
   // location is an address, it will be be returned whether or not the address
   // is inside this module (it will be symbolized if possible). If the input is
@@ -85,6 +99,8 @@
   fxl::RefPtr<SystemSymbols::ModuleRef> module_;
 
   uint64_t load_address_;
+  std::string build_id_;
+  std::vector<debug_ipc::ElfSymbol> elf_symbols_;
   SymbolContext symbol_context_;
 
   FXL_DISALLOW_COPY_AND_ASSIGN(LoadedModuleSymbols);
diff --git a/bin/zxdb/symbols/process_symbols.cc b/bin/zxdb/symbols/process_symbols.cc
index fd793e4..f2b4fd3 100644
--- a/bin/zxdb/symbols/process_symbols.cc
+++ b/bin/zxdb/symbols/process_symbols.cc
@@ -211,11 +211,12 @@
     // Error, but it may be expected.
     if (!ExpectSymbolsForName(module.name))
       *symbol_load_err = Err();
-    info.symbols = std::make_unique<LoadedModuleSymbols>(nullptr, module.base);
+    info.symbols = std::make_unique<LoadedModuleSymbols>(
+        nullptr, module.build_id, module.base);
   } else {
     // Success, make the LoadedModuleSymbols.
     info.symbols = std::make_unique<LoadedModuleSymbols>(
-        std::move(module_symbols), module.base);
+        std::move(module_symbols), module.build_id, module.base);
   }
 
   auto inserted_iter =
diff --git a/bin/zxdb/symbols/process_symbols_test_setup.cc b/bin/zxdb/symbols/process_symbols_test_setup.cc
index 5e6b135..32c2437 100644
--- a/bin/zxdb/symbols/process_symbols_test_setup.cc
+++ b/bin/zxdb/symbols/process_symbols_test_setup.cc
@@ -21,7 +21,8 @@
     const std::string& name, const std::string& build_id, uint64_t base,
     std::unique_ptr<ModuleSymbols> mod_sym) {
   auto loaded = std::make_unique<LoadedModuleSymbols>(
-      system_.InjectModuleForTesting(build_id, std::move(mod_sym)), base);
+      system_.InjectModuleForTesting(build_id, std::move(mod_sym)), build_id,
+      base);
   process_.InjectModuleForTesting(name, build_id, std::move(loaded));
 }