JDevlieghere created this revision.
JDevlieghere added reviewers: mib, jingham.
Herald added a project: All.
JDevlieghere requested review of this revision.

This patch adds support for creating modules from JSON object files. This is 
necessary for crashlogs (see c17a1f3df70b 
<https://reviews.llvm.org/rGc17a1f3df70b69323a5f3153c44e04533cb0a481> for more 
details) where we don't have neither the module nor the symbol file.


https://reviews.llvm.org/D148062

Files:
  lldb/include/lldb/Core/Section.h
  lldb/include/lldb/Symbol/ObjectFile.h
  lldb/source/Core/Section.cpp
  lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp
  lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.h
  lldb/source/Symbol/ObjectFile.cpp
  lldb/test/API/macosx/symbols/TestObjectFileJSON.py

Index: lldb/test/API/macosx/symbols/TestObjectFileJSON.py
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/symbols/TestObjectFileJSON.py
@@ -0,0 +1,100 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+import json
+import uuid
+import os
+import shutil
+
+
+class TestObjectFileJSOn(TestBase):
+    TRIPLE = "arm64-apple-macosx13.0.0"
+
+    def setUp(self):
+        TestBase.setUp(self)
+        self.source = "main.c"
+
+    def emitJSON(self, data, path):
+        json_object = json.dumps(data, indent=4)
+        json_object_file = self.getBuildArtifact("a.json")
+        with open(json_object_file, "w") as outfile:
+            outfile.write(json_object)
+
+    def toModuleSpec(self, path):
+        module_spec = lldb.SBModuleSpec()
+        module_spec.SetFileSpec(lldb.SBFileSpec(path))
+        return module_spec
+
+    @no_debug_info_test
+    def test_target(self):
+        data = {
+            "triple": self.TRIPLE,
+            "uuid": str(uuid.uuid4()),
+            "type": "executable",
+        }
+
+        json_object_file = self.getBuildArtifact("a.json")
+        self.emitJSON(data, json_object_file)
+
+        target = self.dbg.CreateTarget(json_object_file)
+        self.assertTrue(target.IsValid())
+        self.assertEqual(target.GetTriple(), self.TRIPLE)
+
+    @no_debug_info_test
+    def test_module(self):
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+
+        data = {
+            "triple": self.TRIPLE,
+            "uuid": str(uuid.uuid4()),
+        }
+
+        json_object_file = self.getBuildArtifact("a.json")
+        self.emitJSON(data, json_object_file)
+
+        module = target.AddModule(self.toModuleSpec(json_object_file))
+        self.assertFalse(module.IsValid())
+
+        data = {
+            "triple": self.TRIPLE,
+            "uuid": str(uuid.uuid4()),
+            "type": "sharedlibrary",
+            "sections": [
+                {
+                    "name": "__TEXT",
+                    "type": "code",
+                    "address": 0,
+                    "size": 0x222,
+                }
+            ],
+            "symbols": [
+                {
+                    "name": "foo",
+                    "address": 0x100,
+                    "size": 0x11,
+                }
+            ],
+        }
+        self.emitJSON(data, json_object_file)
+
+        module = target.AddModule(self.toModuleSpec(json_object_file))
+        self.assertTrue(module.IsValid())
+
+        section = module.GetSectionAtIndex(0)
+        self.assertTrue(section.IsValid())
+        self.assertEqual(section.GetName(), "__TEXT")
+        self.assertEqual(section.file_addr, 0x0)
+        self.assertEqual(section.size, 0x222)
+
+        symbol = module.FindSymbol("foo")
+        self.assertTrue(symbol.IsValid())
+        self.assertEqual(symbol.addr.GetFileAddress(), 0x100)
+        self.assertEqual(symbol.GetSize(), 0x11)
+
+        error = target.SetSectionLoadAddress(section, 0x1000)
+        self.assertSuccess(error)
+        self.assertEqual(symbol.addr.GetLoadAddress(target), 0x1100)
Index: lldb/source/Symbol/ObjectFile.cpp
===================================================================
--- lldb/source/Symbol/ObjectFile.cpp
+++ lldb/source/Symbol/ObjectFile.cpp
@@ -761,3 +761,34 @@
   m_cache_hash = llvm::djbHash(strm.GetString());
   return *m_cache_hash;
 }
+
+namespace llvm {
+namespace json {
+
+bool fromJSON(const llvm::json::Value &value,
+              lldb_private::ObjectFile::Type &type, llvm::json::Path path) {
+  if (auto str = value.getAsString()) {
+    type = llvm::StringSwitch<ObjectFile::Type>(*str)
+               .Case("corefile", ObjectFile::eTypeCoreFile)
+               .Case("executable", ObjectFile::eTypeExecutable)
+               .Case("debuginfo", ObjectFile::eTypeDebugInfo)
+               .Case("dynamiclinker", ObjectFile::eTypeDynamicLinker)
+               .Case("objectfile", ObjectFile::eTypeObjectFile)
+               .Case("sharedlibrary", ObjectFile::eTypeSharedLibrary)
+               .Case("stublibrary", ObjectFile::eTypeStubLibrary)
+               .Case("jit", ObjectFile::eTypeJIT)
+               .Case("unknown", ObjectFile::eTypeUnknown)
+               .Default(ObjectFile::eTypeInvalid);
+
+    if (type == ObjectFile::eTypeInvalid) {
+      path.report("invalid object type");
+      return false;
+    }
+
+    return true;
+  }
+  path.report("expected string");
+  return false;
+}
+} // namespace json
+} // namespace llvm
Index: lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.h
===================================================================
--- lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.h
+++ lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.h
@@ -82,7 +82,7 @@
 
   uint32_t GetDependentModules(FileSpecList &files) override { return 0; }
 
-  Type CalculateType() override { return eTypeDebugInfo; }
+  Type CalculateType() override { return m_type; }
 
   Strata CalculateStrata() override { return eStrataUser; }
 
@@ -92,21 +92,27 @@
   struct Header {
     std::string triple;
     std::string uuid;
+    std::optional<ObjectFile::Type> type;
   };
 
   struct Body {
+    std::vector<JSONSection> sections;
     std::vector<JSONSymbol> symbols;
   };
 
 private:
   ArchSpec m_arch;
   UUID m_uuid;
+  ObjectFile::Type m_type;
+  std::optional<uint64_t> m_size;
   std::vector<JSONSymbol> m_symbols;
+  std::vector<JSONSection> m_sections;
 
   ObjectFileJSON(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
                  lldb::offset_t data_offset, const FileSpec *file,
                  lldb::offset_t offset, lldb::offset_t length, ArchSpec arch,
-                 UUID uuid, std::vector<JSONSymbol> symbols);
+                 UUID uuid, Type type, std::vector<JSONSymbol> symbols,
+                 std::vector<JSONSection> sections);
 };
 
 bool fromJSON(const llvm::json::Value &value, ObjectFileJSON::Header &header,
Index: lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp
+++ lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp
@@ -73,13 +73,14 @@
   ArchSpec arch(header.triple);
   UUID uuid;
   uuid.SetFromStringRef(header.uuid);
+  Type type = header.type.value_or(eTypeDebugInfo);
 
   Body body;
   fromJSON(*json, body, root);
 
   return new ObjectFileJSON(module_sp, data_sp, data_offset, file, file_offset,
-                            length, std::move(arch), std::move(uuid),
-                            std::move(body.symbols));
+                            length, std::move(arch), std::move(uuid), type,
+                            std::move(body.symbols), std::move(body.sections));
 }
 
 ObjectFile *ObjectFileJSON::CreateMemoryInstance(const ModuleSP &module_sp,
@@ -123,10 +124,12 @@
 ObjectFileJSON::ObjectFileJSON(const ModuleSP &module_sp, DataBufferSP &data_sp,
                                offset_t data_offset, const FileSpec *file,
                                offset_t offset, offset_t length, ArchSpec arch,
-                               UUID uuid, std::vector<JSONSymbol> symbols)
+                               UUID uuid, Type type,
+                               std::vector<JSONSymbol> symbols,
+                               std::vector<JSONSection> sections)
     : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
-      m_arch(std::move(arch)), m_uuid(std::move(uuid)),
-      m_symbols(std::move(symbols)) {}
+      m_arch(std::move(arch)), m_uuid(std::move(uuid)), m_type(type),
+      m_symbols(std::move(symbols)), m_sections(std::move(sections)) {}
 
 bool ObjectFileJSON::ParseHeader() {
   // We already parsed the header during initialization.
@@ -147,7 +150,21 @@
   symtab.Finalize();
 }
 
-void ObjectFileJSON::CreateSections(SectionList &unified_section_list) {}
+void ObjectFileJSON::CreateSections(SectionList &unified_section_list) {
+  if (m_sections_up)
+    return;
+  m_sections_up = std::make_unique<SectionList>();
+
+  lldb::user_id_t id = 1;
+  for (const auto &section : m_sections) {
+    auto section_sp = std::make_shared<Section>(
+        GetModule(), this, id++, ConstString(section.name),
+        section.type.value_or(eSectionTypeCode), 0, section.size.value_or(0),
+        section.address.value_or(0), 0, /*log2align*/ 0, /*flags*/ 0);
+    m_sections_up->AddSection(section_sp);
+    unified_section_list.AddSection(section_sp);
+  }
+}
 
 bool ObjectFileJSON::MagicBytesMatch(DataBufferSP data_sp,
                                      lldb::addr_t data_offset,
@@ -164,13 +181,26 @@
 bool fromJSON(const json::Value &value, ObjectFileJSON::Header &header,
               json::Path path) {
   json::ObjectMapper o(value, path);
-  return o && o.map("triple", header.triple) && o.map("uuid", header.uuid);
+  return o && o.map("triple", header.triple) && o.map("uuid", header.uuid) &&
+         o.map("type", header.type);
 }
 
 bool fromJSON(const json::Value &value, ObjectFileJSON::Body &body,
               json::Path path) {
+  std::optional<std::vector<JSONSymbol>> symbols;
+  std::optional<std::vector<JSONSection>> sections;
+
   json::ObjectMapper o(value, path);
-  return o && o.map("symbols", body.symbols);
+  const bool mapped =
+      o && o.map("symbols", symbols) && o.map("sections", sections);
+
+  if (!mapped)
+    return false;
+
+  body.symbols = symbols.value_or(std::vector<JSONSymbol>{});
+  body.sections = sections.value_or(std::vector<JSONSection>{});
+
+  return true;
 }
 
 } // namespace lldb_private
Index: lldb/source/Core/Section.cpp
===================================================================
--- lldb/source/Core/Section.cpp
+++ lldb/source/Core/Section.cpp
@@ -673,3 +673,36 @@
   }
   return debug_info_size;
 }
+
+namespace llvm {
+namespace json {
+
+bool fromJSON(const llvm::json::Value &value,
+              lldb_private::JSONSection &section, llvm::json::Path path) {
+  llvm::json::ObjectMapper o(value, path);
+  return o && o.map("name", section.name) && o.map("type", section.type) &&
+         o.map("size", section.address) && o.map("size", section.size);
+}
+
+bool fromJSON(const llvm::json::Value &value, lldb::SectionType &type,
+              llvm::json::Path path) {
+  if (auto str = value.getAsString()) {
+    type = llvm::StringSwitch<lldb::SectionType>(*str)
+               .Case("code", eSectionTypeCode)
+               .Case("container", eSectionTypeContainer)
+               .Case("data", eSectionTypeData)
+               .Case("debug", eSectionTypeDebug)
+               .Default(eSectionTypeInvalid);
+
+    if (type == eSectionTypeInvalid) {
+      path.report("invalid section type");
+      return false;
+    }
+
+    return true;
+  }
+  path.report("expected string");
+  return false;
+}
+} // namespace json
+} // namespace llvm
Index: lldb/include/lldb/Symbol/ObjectFile.h
===================================================================
--- lldb/include/lldb/Symbol/ObjectFile.h
+++ lldb/include/lldb/Symbol/ObjectFile.h
@@ -768,6 +768,11 @@
   static void format(const lldb_private::ObjectFile::Strata &strata,
                      raw_ostream &OS, StringRef Style);
 };
+
+namespace json {
+bool fromJSON(const llvm::json::Value &value, lldb_private::ObjectFile::Type &,
+              llvm::json::Path path);
+} // namespace json
 } // namespace llvm
 
 #endif // LLDB_SYMBOL_OBJECTFILE_H
Index: lldb/include/lldb/Core/Section.h
===================================================================
--- lldb/include/lldb/Core/Section.h
+++ lldb/include/lldb/Core/Section.h
@@ -17,6 +17,7 @@
 #include "lldb/lldb-enumerations.h"
 #include "lldb/lldb-forward.h"
 #include "lldb/lldb-types.h"
+#include "llvm/Support/JSON.h"
 
 #include <memory>
 #include <vector>
@@ -99,6 +100,13 @@
   collection m_sections;
 };
 
+struct JSONSection {
+  std::string name;
+  std::optional<lldb::SectionType> type;
+  std::optional<uint64_t> address;
+  std::optional<uint64_t> size;
+};
+
 class Section : public std::enable_shared_from_this<Section>,
                 public ModuleChild,
                 public UserID,
@@ -287,4 +295,16 @@
 
 } // namespace lldb_private
 
+namespace llvm {
+namespace json {
+
+bool fromJSON(const llvm::json::Value &value,
+              lldb_private::JSONSection &section, llvm::json::Path path);
+
+bool fromJSON(const llvm::json::Value &value, lldb::SectionType &type,
+              llvm::json::Path path);
+
+} // namespace json
+} // namespace llvm
+
 #endif // LLDB_CORE_SECTION_H
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to