Skip to content

Add subsection and permissions support to ObjectFileJSON. #129801

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 5, 2025

Conversation

clayborg
Copy link
Collaborator

@clayborg clayborg commented Mar 4, 2025

This patch adds the ability to create subsections in a section and allows permissions to be specified.

This patch adds the ability to create subsections in a section and allows permissions to be specified.
@clayborg clayborg requested a review from JDevlieghere as a code owner March 4, 2025 23:42
@llvmbot llvmbot added the lldb label Mar 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 4, 2025

@llvm/pr-subscribers-lldb

Author: Greg Clayton (clayborg)

Changes

This patch adds the ability to create subsections in a section and allows permissions to be specified.


Full diff: https://github.com/llvm/llvm-project/pull/129801.diff

4 Files Affected:

  • (modified) lldb/include/lldb/Core/Section.h (+5)
  • (modified) lldb/source/Core/Section.cpp (+5-1)
  • (modified) lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp (+47-12)
  • (modified) lldb/test/API/functionalities/json/object-file/TestObjectFileJSON.py (+55-12)
diff --git a/lldb/include/lldb/Core/Section.h b/lldb/include/lldb/Core/Section.h
index 4bf73e2e5a068..17b3cb454949f 100644
--- a/lldb/include/lldb/Core/Section.h
+++ b/lldb/include/lldb/Core/Section.h
@@ -105,6 +105,11 @@ struct JSONSection {
   std::optional<lldb::SectionType> type;
   std::optional<uint64_t> address;
   std::optional<uint64_t> size;
+  // Section permissions;
+  std::optional<bool> read;
+  std::optional<bool> write;
+  std::optional<bool> execute;
+  std::vector<JSONSection> subsections;
 };
 
 class Section : public std::enable_shared_from_this<Section>,
diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp
index 96410a1ad497c..72a466a9bed40 100644
--- a/lldb/source/Core/Section.cpp
+++ b/lldb/source/Core/Section.cpp
@@ -690,7 +690,11 @@ 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("address", section.address) && o.map("size", section.size);
+         o.map("address", section.address) && o.map("size", section.size) &&
+         o.map("read", section.read) &&
+         o.map("write", section.write) &&
+         o.map("execute", section.execute) &&
+         o.mapOptional("subsections", section.subsections);
 }
 
 bool fromJSON(const llvm::json::Value &value, lldb::SectionType &type,
diff --git a/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp b/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp
index 8e90fac46f348..de939fdefaebb 100644
--- a/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp
+++ b/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp
@@ -180,18 +180,53 @@ void ObjectFileJSON::CreateSections(SectionList &unified_section_list) {
   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,
-        /*sect_id=*/id++,
-        /*name=*/ConstString(section.name),
-        /*sect_type=*/section.type.value_or(eSectionTypeCode),
-        /*file_vm_addr=*/section.address.value_or(0),
-        /*vm_size=*/section.size.value_or(0),
-        /*file_offset=*/0,
-        /*file_size=*/0,
-        /*log2align=*/0,
-        /*flags=*/0);
+  for (const auto &json_section : m_sections) {
+    auto make_section = [this, &id](const JSONSection &section,
+                               SectionSP parent_section_sp = nullptr) -> SectionSP {
+      SectionSP section_sp;
+      if (parent_section_sp) {
+        section_sp = std::make_shared<Section>(
+            parent_section_sp, GetModule(), this,
+            /*sect_id=*/id++,
+            /*name=*/ConstString(section.name),
+            /*sect_type=*/section.type.value_or(eSectionTypeCode),
+            /*file_vm_addr=*/section.address.value_or(0) - parent_section_sp->GetFileAddress(),
+            /*vm_size=*/section.size.value_or(0),
+            /*file_offset=*/0,
+            /*file_size=*/0,
+            /*log2align=*/0,
+            /*flags=*/0);
+
+      } else {
+        section_sp = std::make_shared<Section>(
+            GetModule(), this,
+            /*sect_id=*/id++,
+            /*name=*/ConstString(section.name),
+            /*sect_type=*/section.type.value_or(eSectionTypeCode),
+            /*file_vm_addr=*/section.address.value_or(0),
+            /*vm_size=*/section.size.value_or(0),
+            /*file_offset=*/0,
+            /*file_size=*/0,
+            /*log2align=*/0,
+            /*flags=*/0);
+      }
+      uint32_t permissions = 0;
+      if (section.read.value_or(0))
+        permissions |= lldb::ePermissionsReadable;
+      if (section.write.value_or(0))
+        permissions |= lldb::ePermissionsWritable;
+      if (section.execute.value_or(0))
+        permissions |= lldb::ePermissionsExecutable;
+      if (permissions)
+        section_sp->SetPermissions(permissions);
+      return section_sp;
+    };
+    auto section_sp = make_section(json_section);
+    for (const auto &subsection : json_section.subsections) {
+      SectionSP subsection_sp = make_section(subsection, section_sp);
+      section_sp->GetChildren().AddSection(subsection_sp);
+    }
+
     m_sections_up->AddSection(section_sp);
     unified_section_list.AddSection(section_sp);
   }
diff --git a/lldb/test/API/functionalities/json/object-file/TestObjectFileJSON.py b/lldb/test/API/functionalities/json/object-file/TestObjectFileJSON.py
index eee0144ad5706..255704d6e159d 100644
--- a/lldb/test/API/functionalities/json/object-file/TestObjectFileJSON.py
+++ b/lldb/test/API/functionalities/json/object-file/TestObjectFileJSON.py
@@ -75,15 +75,32 @@ def test_module(self):
             "sections": [
                 {
                     "name": "__TEXT",
-                    "type": "code",
+                    "type": "container",
                     "address": TEXT_file_addr,
                     "size": TEXT_size,
+                    "read": True,
+                    "write": False,
+                    "execute": True,
+                    "subsections": [
+                        {
+                            "name": "__text",
+                            "type": "code",
+                            "address": TEXT_file_addr,
+                            "size": TEXT_size,
+                            "read": True,
+                            "write": False,
+                            "execute": True
+                        }
+                    ]
                 },
                 {
                     "name": "__DATA",
-                    "type": "code",
+                    "type": "data",
                     "address": DATA_file_addr,
                     "size": DATA_size,
+                    "read": True,
+                    "write": True,
+                    "execute": False
                 }
             ],
             "symbols": [
@@ -108,17 +125,43 @@ def test_module(self):
         module = target.AddModule(self.toModuleSpec(json_object_file_c))
         self.assertTrue(module.IsValid())
 
-        text_section = module.GetSectionAtIndex(0)
+        TEXT_section = module.GetSectionAtIndex(0)
+        self.assertTrue(TEXT_section.IsValid())
+        self.assertEqual(TEXT_section.GetName(), "__TEXT")
+        self.assertEqual(TEXT_section.file_addr, TEXT_file_addr)
+        self.assertEqual(TEXT_section.size, TEXT_size)
+        self.assertEqual(TEXT_section.GetSectionType(),
+                         lldb.eSectionTypeContainer)
+        self.assertEqual(TEXT_section.GetNumSubSections(), 1)
+        text_permissions = TEXT_section.GetPermissions()
+        self.assertTrue((text_permissions & lldb.ePermissionsReadable) != 0)
+        self.assertFalse((text_permissions & lldb.ePermissionsWritable) != 0)
+        self.assertTrue((text_permissions & lldb.ePermissionsExecutable) != 0)
+
+        text_section = TEXT_section.GetSubSectionAtIndex(0)
         self.assertTrue(text_section.IsValid())
-        self.assertEqual(text_section.GetName(), "__TEXT")
+        self.assertEqual(text_section.GetName(), "__text")
         self.assertEqual(text_section.file_addr, TEXT_file_addr)
         self.assertEqual(text_section.size, TEXT_size)
-
-        data_section = module.GetSectionAtIndex(1)
-        self.assertTrue(data_section.IsValid())
-        self.assertEqual(data_section.GetName(), "__DATA")
-        self.assertEqual(data_section.file_addr, DATA_file_addr)
-        self.assertEqual(data_section.size, DATA_size)
+        self.assertEqual(text_section.GetSectionType(),
+                         lldb.eSectionTypeCode)
+        self.assertEqual(text_section.GetNumSubSections(), 0)
+        text_permissions = text_section.GetPermissions()
+        self.assertTrue((text_permissions & lldb.ePermissionsReadable) != 0)
+        self.assertFalse((text_permissions & lldb.ePermissionsWritable) != 0)
+        self.assertTrue((text_permissions & lldb.ePermissionsExecutable) != 0)
+
+        DATA_section = module.GetSectionAtIndex(1)
+        self.assertTrue(DATA_section.IsValid())
+        self.assertEqual(DATA_section.GetName(), "__DATA")
+        self.assertEqual(DATA_section.file_addr, DATA_file_addr)
+        self.assertEqual(DATA_section.size, DATA_size)
+        self.assertEqual(DATA_section.GetSectionType(),
+                         lldb.eSectionTypeData)
+        data_permissions = DATA_section.GetPermissions()
+        self.assertTrue((data_permissions & lldb.ePermissionsReadable) != 0)
+        self.assertTrue((data_permissions & lldb.ePermissionsWritable) != 0)
+        self.assertFalse((data_permissions & lldb.ePermissionsExecutable) != 0)
 
         foo_symbol = module.FindSymbol("foo")
         self.assertTrue(foo_symbol.IsValid())
@@ -130,9 +173,9 @@ def test_module(self):
         self.assertEqual(bar_symbol.addr.GetFileAddress(), bar_file_addr)
         self.assertEqual(bar_symbol.GetSize(), bar_size)
 
-        error = target.SetSectionLoadAddress(text_section, TEXT_file_addr + slide)
+        error = target.SetSectionLoadAddress(TEXT_section, TEXT_file_addr + slide)
         self.assertSuccess(error)
-        error = target.SetSectionLoadAddress(data_section, DATA_file_addr + slide)
+        error = target.SetSectionLoadAddress(DATA_section, DATA_file_addr + slide)
         self.assertSuccess(error)
         self.assertEqual(foo_symbol.addr.GetLoadAddress(target), foo_file_addr + slide)
         self.assertEqual(bar_symbol.addr.GetLoadAddress(target), bar_file_addr + slide)

Copy link

github-actions bot commented Mar 4, 2025

⚠️ Python code formatter, darker found issues in your code. ⚠️

You can test this locally with the following command:
darker --check --diff -r 7b596ce362829281ea73b576774ce90bb212138d...bf7e4a6c6079262adec17134debf1022450e05f7 lldb/test/API/functionalities/json/object-file/TestObjectFileJSON.py
View the diff from darker here.
--- TestObjectFileJSON.py	2025-03-04 23:41:27.000000 +0000
+++ TestObjectFileJSON.py	2025-03-05 00:08:39.394202 +0000
@@ -87,23 +87,23 @@
                             "type": "code",
                             "address": TEXT_file_addr,
                             "size": TEXT_size,
                             "read": True,
                             "write": False,
-                            "execute": True
+                            "execute": True,
                         }
-                    ]
+                    ],
                 },
                 {
                     "name": "__DATA",
                     "type": "data",
                     "address": DATA_file_addr,
                     "size": DATA_size,
                     "read": True,
                     "write": True,
-                    "execute": False
-                }
+                    "execute": False,
+                },
             ],
             "symbols": [
                 {
                     "name": "foo",
                     "type": "code",
@@ -128,12 +128,11 @@
         TEXT_section = module.GetSectionAtIndex(0)
         self.assertTrue(TEXT_section.IsValid())
         self.assertEqual(TEXT_section.GetName(), "__TEXT")
         self.assertEqual(TEXT_section.file_addr, TEXT_file_addr)
         self.assertEqual(TEXT_section.size, TEXT_size)
-        self.assertEqual(TEXT_section.GetSectionType(),
-                         lldb.eSectionTypeContainer)
+        self.assertEqual(TEXT_section.GetSectionType(), lldb.eSectionTypeContainer)
         self.assertEqual(TEXT_section.GetNumSubSections(), 1)
         text_permissions = TEXT_section.GetPermissions()
         self.assertTrue((text_permissions & lldb.ePermissionsReadable) != 0)
         self.assertFalse((text_permissions & lldb.ePermissionsWritable) != 0)
         self.assertTrue((text_permissions & lldb.ePermissionsExecutable) != 0)
@@ -141,12 +140,11 @@
         text_section = TEXT_section.GetSubSectionAtIndex(0)
         self.assertTrue(text_section.IsValid())
         self.assertEqual(text_section.GetName(), "__text")
         self.assertEqual(text_section.file_addr, TEXT_file_addr)
         self.assertEqual(text_section.size, TEXT_size)
-        self.assertEqual(text_section.GetSectionType(),
-                         lldb.eSectionTypeCode)
+        self.assertEqual(text_section.GetSectionType(), lldb.eSectionTypeCode)
         self.assertEqual(text_section.GetNumSubSections(), 0)
         text_permissions = text_section.GetPermissions()
         self.assertTrue((text_permissions & lldb.ePermissionsReadable) != 0)
         self.assertFalse((text_permissions & lldb.ePermissionsWritable) != 0)
         self.assertTrue((text_permissions & lldb.ePermissionsExecutable) != 0)
@@ -154,12 +152,11 @@
         DATA_section = module.GetSectionAtIndex(1)
         self.assertTrue(DATA_section.IsValid())
         self.assertEqual(DATA_section.GetName(), "__DATA")
         self.assertEqual(DATA_section.file_addr, DATA_file_addr)
         self.assertEqual(DATA_section.size, DATA_size)
-        self.assertEqual(DATA_section.GetSectionType(),
-                         lldb.eSectionTypeData)
+        self.assertEqual(DATA_section.GetSectionType(), lldb.eSectionTypeData)
         data_permissions = DATA_section.GetPermissions()
         self.assertTrue((data_permissions & lldb.ePermissionsReadable) != 0)
         self.assertTrue((data_permissions & lldb.ePermissionsWritable) != 0)
         self.assertFalse((data_permissions & lldb.ePermissionsExecutable) != 0)
 

Copy link

github-actions bot commented Mar 4, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@clayborg clayborg merged commit 27901ce into llvm:main Mar 5, 2025
6 of 9 checks passed
@clayborg clayborg deleted the objfile-json-subsections-permissions branch March 5, 2025 00:19
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
This patch adds the ability to create subsections in a section and
allows permissions to be specified.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants