[Lldb-commits] [lldb] [lldb] Enforce that ArchDefaultUnwindPlans declare other regs unfetch (PR #203684)

Jason Molenda via lldb-commits lldb-commits at lists.llvm.org
Sat Jun 13 16:09:51 PDT 2026


https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/203684

>From aeef169c1ea5f80014331b8fe8d13cbe825ebdb3 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Sat, 13 Jun 2026 00:39:45 -0700
Subject: [PATCH 1/5] [lldb] Enforce that ArchDefaultUnwindPlans declare other
 regs unfetch

I noticed a few of the ABI plugins were not setting
UnspecifiedRegistersAreUndefined()==true in their UnwindPlan
rows.  This prevents the unwind engine from trying to fetch
registers from any newer stack frames.

The arch default unwind plans are used by lldb when it doesn't have
any accurate information about the registers a function has spilled
to stack, or where -- it only knows enough to continue walking the
stack, assuming all the functions have stored the caller's pc & fp
to stack.  It is the last-ditch fallback when we backtrace through
no-symbol / no-unwind info code.

Normally when the unwind engine does not see a non-volatile aka
callee-preserved register mentioned in an UnwindPlan, that means
this function did not save the register to stack, it left the reg
contents unmodified.  So if we are looking for x12 in frame 3, and
frame 2 doesn't mention x12 in its UnwindPlan, we will look in frame
1 to see if it spilled x12 to stack.  If not, then we look at frame
0 and if it also hasn't spilled it, we copy the x12 value from the
live register context and use it in frame 3.

Arch default unwind plans are dangerous if they allow this to happen
because we don't know if a stack frame saved a register to stack
and then changed the value in the register.  It's unsafe for us to
make any assumptions about any register not explicitly listed in
the UnwindPlan.

I added debug-build asserts for all uses of an ArchDefaultUnwindPlan
to enforce this and catch any future introductions of the mistake.
Very easy to do unintentionally in new ABIs.
---
 lldb/include/lldb/Symbol/UnwindPlan.h             |  2 +-
 lldb/source/Commands/CommandObjectTarget.cpp      |  7 +++++++
 .../Plugins/ABI/LoongArch/ABISysV_loongarch.cpp   |  1 +
 lldb/source/Plugins/ABI/MSP430/ABISysV_msp430.cpp |  1 +
 lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp   |  1 +
 lldb/source/Symbol/FuncUnwinders.cpp              | 11 ++++++++++-
 lldb/source/Target/RegisterContextUnwind.cpp      | 15 +++++++++++++++
 7 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/lldb/include/lldb/Symbol/UnwindPlan.h b/lldb/include/lldb/Symbol/UnwindPlan.h
index fe8081f83c590..99d948f8b8a8c 100644
--- a/lldb/include/lldb/Symbol/UnwindPlan.h
+++ b/lldb/include/lldb/Symbol/UnwindPlan.h
@@ -409,7 +409,7 @@ class UnwindPlan {
       m_unspecified_registers_are_undefined = unspec_is_undef;
     }
 
-    bool GetUnspecifiedRegistersAreUndefined() {
+    bool GetUnspecifiedRegistersAreUndefined() const {
       return m_unspecified_registers_are_undefined;
     }
 
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 56e0dfef34444..49b2c43c52222 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -3786,6 +3786,13 @@ class CommandObjectTargetModulesShowUnwind : public CommandObjectParsed {
       ABISP abi_sp = process->GetABI();
       if (abi_sp) {
         if (UnwindPlanSP plan_sp = abi_sp->CreateDefaultUnwindPlan()) {
+#ifndef NDEBUG
+          if (plan_sp && plan_sp->GetRowCount() > 0)
+            assert(plan_sp->GetRowAtIndex(0)
+                       ->GetUnspecifiedRegistersAreUndefined() &&
+                   "Default UnwindPlan must set "
+                   "UnspecifiedRegistersAreUndefined to true");
+#endif
           result.GetOutputStream().Printf("Arch default UnwindPlan:\n");
           plan_sp->Dump(result.GetOutputStream(), thread.get(),
                         LLDB_INVALID_ADDRESS);
diff --git a/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp b/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp
index d2a2cbe0643ac..0c4495be9a7ba 100644
--- a/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp
+++ b/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp
@@ -566,6 +566,7 @@ UnwindPlanSP ABISysV_loongarch::CreateDefaultUnwindPlan() {
   // have been spilled to stack already.
   row.SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, reg_size * -2, true);
   row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, reg_size * -1, true);
+  row.SetUnspecifiedRegistersAreUndefined(true);
 
   auto plan_sp = std::make_shared<UnwindPlan>(eRegisterKindGeneric);
   plan_sp->AppendRow(std::move(row));
diff --git a/lldb/source/Plugins/ABI/MSP430/ABISysV_msp430.cpp b/lldb/source/Plugins/ABI/MSP430/ABISysV_msp430.cpp
index af7ef03b94c4c..da2c01b4a2ad4 100644
--- a/lldb/source/Plugins/ABI/MSP430/ABISysV_msp430.cpp
+++ b/lldb/source/Plugins/ABI/MSP430/ABISysV_msp430.cpp
@@ -331,6 +331,7 @@ UnwindPlanSP ABISysV_msp430::CreateDefaultUnwindPlan() {
   row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -2, true);
   row.SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
   row.SetRegisterLocationToUnspecified(fp_reg_num, true);
+  row.SetUnspecifiedRegistersAreUndefined(true);
 
   auto plan_sp = std::make_shared<UnwindPlan>(eRegisterKindDWARF);
   plan_sp->AppendRow(std::move(row));
diff --git a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
index bf0e5a15ad790..f056b7958c063 100644
--- a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
+++ b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
@@ -753,6 +753,7 @@ UnwindPlanSP ABISysV_riscv::CreateDefaultUnwindPlan() {
   // have been spilled to stack already.
   row.SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, reg_size * -2, true);
   row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, reg_size * -1, true);
+  row.SetUnspecifiedRegistersAreUndefined(true);
 
   auto plan_sp = std::make_shared<UnwindPlan>(eRegisterKindGeneric);
   plan_sp->AppendRow(std::move(row));
diff --git a/lldb/source/Symbol/FuncUnwinders.cpp b/lldb/source/Symbol/FuncUnwinders.cpp
index fffc35d7f6177..c0052fff280c6 100644
--- a/lldb/source/Symbol/FuncUnwinders.cpp
+++ b/lldb/source/Symbol/FuncUnwinders.cpp
@@ -459,8 +459,17 @@ FuncUnwinders::GetUnwindPlanArchitectureDefault(Thread &thread) {
 
   ProcessSP process_sp(thread.CalculateProcess());
   if (process_sp) {
-    if (ABI *abi = process_sp->GetABI().get())
+    if (ABI *abi = process_sp->GetABI().get()) {
       m_unwind_plan_arch_default_sp = abi->CreateDefaultUnwindPlan();
+#ifndef NDEBUG
+      if (m_unwind_plan_arch_default_sp &&
+          m_unwind_plan_arch_default_sp->GetRowCount() > 0)
+        assert(m_unwind_plan_arch_default_sp->GetRowAtIndex(0)
+                   ->GetUnspecifiedRegistersAreUndefined() &&
+               "Default UnwindPlan must set UnspecifiedRegistersAreUndefined "
+               "to true");
+#endif
+    }
   }
 
   return m_unwind_plan_arch_default_sp;
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index 139387db7a04f..fe934cb6c9e97 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -442,6 +442,13 @@ void RegisterContextUnwind::InitializeNonZerothFrame() {
     if (abi_sp) {
       m_fast_unwind_plan_sp.reset();
       m_full_unwind_plan_sp = abi_sp->CreateDefaultUnwindPlan();
+#ifndef NDEBUG
+      if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->GetRowCount() > 0)
+        assert(m_full_unwind_plan_sp->GetRowAtIndex(0)
+                   ->GetUnspecifiedRegistersAreUndefined() &&
+               "Default UnwindPlan must set UnspecifiedRegistersAreUndefined "
+               "to true");
+#endif
       if (m_frame_type != eSkipFrame) // don't override eSkipFrame
       {
         m_frame_type = eNormalFrame;
@@ -810,6 +817,14 @@ RegisterContextUnwind::GetFullUnwindPlanForFrame() {
   ABI *abi = process ? process->GetABI().get() : nullptr;
   if (abi) {
     arch_default_unwind_plan_sp = abi->CreateDefaultUnwindPlan();
+#ifndef NDEBUG
+    if (arch_default_unwind_plan_sp &&
+        arch_default_unwind_plan_sp->GetRowCount() > 0)
+      assert(arch_default_unwind_plan_sp->GetRowAtIndex(0)
+                 ->GetUnspecifiedRegistersAreUndefined() &&
+             "Default UnwindPlan must set UnspecifiedRegistersAreUndefined to "
+             "true");
+#endif
   } else {
     UNWIND_LOG(
         log, "unable to get architectural default UnwindPlan from ABI plugin");

>From 80e66307f71201fbe90340095e97491918d1b43b Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Sat, 13 Jun 2026 01:23:09 -0700
Subject: [PATCH 2/5] Actually don't let registers pass up the stack past a
 UnspecifiedRegistersAreUndefined frame.

---
 lldb/source/Target/RegisterContextUnwind.cpp | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index fe934cb6c9e97..bba33bd851e3f 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1401,7 +1401,16 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
                    "could not convert lldb regnum {0} ({1}) into {2} "
                    "RegisterKind reg numbering scheme",
                    regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), kind);
-      return {};
+      if (active_row && active_row->GetUnspecifiedRegistersAreUndefined()) {
+        UNWIND_LONG(
+            log,
+            "marking register {0} ({1}) as Undefined (volatile) in this "
+            "stack frame because this row is UnspecifiedRegistersAreUndefined.",
+            regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+        unwindplan_regloc.SetUndefined();
+        return unwindplan_regloc;
+        return {};
+      }
     }
 
     if (regnum.IsValid() && active_row &&
@@ -1496,6 +1505,15 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
         }
       }
     }
+    if (active_row && active_row->GetUnspecifiedRegistersAreUndefined()) {
+      UNWIND_LOG(
+          log,
+          "marking register {0} ({1}) as Undefined (volatile) in this "
+          "stack frame because this row is UnspecifiedRegistersAreUndefined.",
+          regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+      unwindplan_regloc.SetUndefined();
+      return unwindplan_regloc;
+    }
   }
 
   ExecutionContext exe_ctx(m_thread.shared_from_this());

>From 27cb53aa881895dfbd51e8322d6ba0c4d966af1e Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Sat, 13 Jun 2026 01:28:52 -0700
Subject: [PATCH 3/5] fix typeo

---
 lldb/source/Target/RegisterContextUnwind.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index bba33bd851e3f..0c20a1124aae4 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1402,7 +1402,7 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
                    "RegisterKind reg numbering scheme",
                    regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), kind);
       if (active_row && active_row->GetUnspecifiedRegistersAreUndefined()) {
-        UNWIND_LONG(
+        UNWIND_LOG(
             log,
             "marking register {0} ({1}) as Undefined (volatile) in this "
             "stack frame because this row is UnspecifiedRegistersAreUndefined.",

>From 72060545b09ecf6caab5fdd2b890cef98d770f1c Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Sat, 13 Jun 2026 01:47:22 -0700
Subject: [PATCH 4/5] typeo

---
 lldb/source/Target/RegisterContextUnwind.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index 0c20a1124aae4..7c780b7980600 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1409,8 +1409,8 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
             regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
         unwindplan_regloc.SetUndefined();
         return unwindplan_regloc;
-        return {};
       }
+      return {};
     }
 
     if (regnum.IsValid() && active_row &&

>From 1f7a3205515e23ddb539b613fe99b9b40bc188b1 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Sat, 13 Jun 2026 16:07:46 -0700
Subject: [PATCH 5/5] Add a testcase to an rv32 corefile. Add stack memory so
 we can backtrace one frame with the DefaultUnwindPlan, check that registers
 are unavailable above the DefaultUnwindPlan.

Also fix a couple of subtle bugs in RegisterContextUnwind
-- m_current_offset and m_current_offset_backed_up_one
changed to std::optional<int> last year, but there were
two places where it was still being used as a simple
integral type.
---
 lldb/source/Target/RegisterContextUnwind.cpp  |  5 ++--
 .../riscv32-corefile/TestRV32MachOCorefile.py | 27 ++++++++++++++++---
 .../riscv32-corefile/riscv32-registers.yaml   | 18 +++++++++++--
 lldb/tools/yaml2macho-core/CoreSpec.cpp       |  4 +++
 lldb/tools/yaml2macho-core/CoreSpec.h         |  3 ++-
 lldb/tools/yaml2macho-core/MemoryWriter.cpp   |  4 +++
 lldb/tools/yaml2macho-core/Utility.cpp        |  6 +++++
 lldb/tools/yaml2macho-core/Utility.h          |  1 +
 8 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index 7c780b7980600..78d6926d5dd70 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -80,7 +80,8 @@ RegisterContextUnwind::RegisterContextUnwind(Thread &thread,
       m_fallback_unwind_plan_sp(), m_all_registers_available(false),
       m_frame_type(-1), m_cfa(LLDB_INVALID_ADDRESS),
       m_afa(LLDB_INVALID_ADDRESS), m_start_pc(), m_current_pc(),
-      m_current_offset(0), m_current_offset_backed_up_one(0),
+      m_current_offset(std::nullopt),
+      m_current_offset_backed_up_one(std::nullopt),
       m_behaves_like_zeroth_frame(false), m_sym_ctx(sym_ctx),
       m_sym_ctx_valid(false), m_frame_number(frame_number), m_registers(),
       m_parent_unwind(unwind_lldb) {
@@ -1014,7 +1015,7 @@ RegisterContextUnwind::GetFullUnwindPlanForFrame() {
     // If we're on the first instruction of a function, and we have an
     // architectural default UnwindPlan for the initial instruction of a
     // function, use that.
-    if (m_current_offset == 0) {
+    if (m_current_offset.has_value() && m_current_offset.value() == 0) {
       unwind_plan_sp =
           func_unwinders_sp->GetUnwindPlanArchitectureDefaultAtFunctionEntry(
               m_thread);
diff --git a/lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py b/lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py
index 449da70fb08ca..b3afdbe1c5608 100644
--- a/lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py
+++ b/lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py
@@ -25,7 +25,7 @@ def test_riscv32_gpr_corefile_registers(self):
         self.assertEqual(process.GetNumThreads(), 2)
 
         thread = process.GetThreadAtIndex(0)
-        self.assertEqual(thread.GetNumFrames(), 1)
+        self.assertEqual(thread.GetNumFrames(), 2)
 
         frame = thread.GetFrameAtIndex(0)
         gpr_regs = frame.registers.GetValueAtIndex(0)
@@ -75,10 +75,31 @@ def test_riscv32_gpr_corefile_registers(self):
 
         idx = 0
         while idx < len(regnames):
-            val = idx | (idx << 8) | (idx << 16) | (idx << 24)
-            self.assertEqual(gpr_regs.GetChildAtIndex(idx).GetValueAsUnsigned(), val)
+            # fp needs to meet specific alignment rules,
+            # so hardcode that value.
+            if regnames[idx] == "fp":
+                self.assertEqual(
+                    gpr_regs.GetChildAtIndex(idx).GetValueAsUnsigned(), 0x08080800
+                )
+            else:
+                val = idx | (idx << 8) | (idx << 16) | (idx << 24)
+                self.assertEqual(
+                    gpr_regs.GetChildAtIndex(idx).GetValueAsUnsigned(), val
+                )
             idx = idx + 1
 
+        # We used an ArchDefaultUnwindPlan to get the second stack frame.
+        # Only pc and fp should be available in this stack frame; any other
+        # register being available is a bug.
+        frame = thread.GetFrameAtIndex(1)
+        gpr_regs = frame.registers.GetValueAtIndex(0)
+
+        # Get pc
+        self.assertEqual(gpr_regs.GetChildAtIndex(32).GetValueAsUnsigned(3), 0x20201020)
+        # Should not be able to read a callee-preserved register, s6
+        self.assertEqual(gpr_regs.GetChildAtIndex(22).GetValueAsUnsigned(3), 3)
+
+        # Check that we can read registers for second thread.
         thread = process.GetThreadAtIndex(1)
         self.assertEqual(thread.GetNumFrames(), 1)
 
diff --git a/lldb/test/API/macosx/riscv32-corefile/riscv32-registers.yaml b/lldb/test/API/macosx/riscv32-corefile/riscv32-registers.yaml
index 81c725f1a4f0e..8163e5ab8b80f 100644
--- a/lldb/test/API/macosx/riscv32-corefile/riscv32-registers.yaml
+++ b/lldb/test/API/macosx/riscv32-corefile/riscv32-registers.yaml
@@ -9,7 +9,7 @@ threads:
           {name: sp, value: 0x02020202}, {name: gp, value: 0x03030303},
           {name: tp, value: 0x04040404}, {name: t0, value: 0x05050505},
           {name: t1, value: 0x06060606}, {name: t2, value: 0x07070707},
-          {name: fp, value: 0x08080808}, {name: s1, value: 0x09090909},
+          {name: fp, value: 0x08080800}, {name: s1, value: 0x09090909},
           {name: a0, value: 0x0a0a0a0a}, {name: a1, value: 0x0b0b0b0b},
           {name: a2, value: 0x0c0c0c0c}, {name: a3, value: 0x0d0d0d0d},
           {name: a4, value: 0x0e0e0e0e}, {name: a5, value: 0x0f0f0f0f},
@@ -30,7 +30,7 @@ threads:
           {name: sp, value: 0x92020202}, {name: gp, value: 0x93030303},
           {name: tp, value: 0x94040404}, {name: t0, value: 0x95050505},
           {name: t1, value: 0x96060606}, {name: t2, value: 0x97070707},
-          {name: fp, value: 0x98080808}, {name: s1, value: 0x99090909},
+          {name: fp, value: 0x98080800}, {name: s1, value: 0x99090909},
           {name: a0, value: 0x9a0a0a0a}, {name: a1, value: 0x9b0b0b0b},
           {name: a2, value: 0x9c0c0c0c}, {name: a3, value: 0x9d0d0d0d},
           {name: a4, value: 0x9e0e0e0e}, {name: a5, value: 0x9f0f0f0f},
@@ -44,3 +44,17 @@ threads:
           {name: t5, value: 0x9e1e1e1e}, {name: t6, value: 0x9f1f1f1f},
           {name: pc, value: 0x90202020}
         ]
+
+memory-regions:
+      # Stack memory giving lldb a saved fp & pc
+      - addr: 0x080807f8
+        UInt32: [ 0x08080700, 0x20201020, 0x00000000 ]
+      # Stack memory for the frame above, indicating end of stack
+      - addr: 0x080806f8
+        UInt32: [ 0x00000000, 0x00000000, 0x00000000 ]
+      # Function address prologue
+      - addr: 0x20201020
+        UInt16: [ 0xb882, 0x1000 ]
+      # Function address prologue
+      - addr: 0x20202020
+        UInt16: [ 0xb882, 0x1000 ]
diff --git a/lldb/tools/yaml2macho-core/CoreSpec.cpp b/lldb/tools/yaml2macho-core/CoreSpec.cpp
index 22551a60b3a5e..cf3215fd06be3 100644
--- a/lldb/tools/yaml2macho-core/CoreSpec.cpp
+++ b/lldb/tools/yaml2macho-core/CoreSpec.cpp
@@ -51,12 +51,16 @@ template <> struct llvm::yaml::MappingTraits<MemoryRegion> {
   static void mapping(IO &io, MemoryRegion &memory) {
     io.mapRequired("addr", memory.addr);
     io.mapOptional("UInt8", memory.bytes);
+    io.mapOptional("UInt16", memory.halfwords);
     io.mapOptional("UInt32", memory.words);
     io.mapOptional("UInt64", memory.doublewords);
 
     if (memory.bytes.size()) {
       memory.type = MemoryType::UInt8;
       memory.size = memory.bytes.size();
+    } else if (memory.halfwords.size()) {
+      memory.type = MemoryType::UInt16;
+      memory.size = memory.halfwords.size() * 2;
     } else if (memory.words.size()) {
       memory.type = MemoryType::UInt32;
       memory.size = memory.words.size() * 4;
diff --git a/lldb/tools/yaml2macho-core/CoreSpec.h b/lldb/tools/yaml2macho-core/CoreSpec.h
index 5c27cc96bdaad..aadd39bd13c4d 100644
--- a/lldb/tools/yaml2macho-core/CoreSpec.h
+++ b/lldb/tools/yaml2macho-core/CoreSpec.h
@@ -37,7 +37,7 @@ struct Thread {
   std::vector<RegisterSet> regsets;
 };
 
-enum MemoryType { UInt8 = 0, UInt32, UInt64 };
+enum MemoryType { UInt8 = 0, UInt16, UInt32, UInt64 };
 
 struct MemoryRegion {
   uint64_t addr;
@@ -45,6 +45,7 @@ struct MemoryRegion {
   uint32_t size;
   // One of the following formats.
   std::vector<uint8_t> bytes;
+  std::vector<uint16_t> halfwords;
   std::vector<uint32_t> words;
   std::vector<uint64_t> doublewords;
 };
diff --git a/lldb/tools/yaml2macho-core/MemoryWriter.cpp b/lldb/tools/yaml2macho-core/MemoryWriter.cpp
index 4ace2894b6be5..139e39e8ac9fe 100644
--- a/lldb/tools/yaml2macho-core/MemoryWriter.cpp
+++ b/lldb/tools/yaml2macho-core/MemoryWriter.cpp
@@ -46,6 +46,10 @@ void create_memory_bytes(const CoreSpec &spec, const MemoryRegion &memory,
     for (uint8_t byte : memory.bytes)
       buf.push_back(byte);
 
+  if (memory.type == MemoryType::UInt16)
+    for (uint16_t halfword : memory.halfwords)
+      add_uint16(buf, halfword);
+
   if (memory.type == MemoryType::UInt32)
     for (uint32_t word : memory.words)
       add_uint32(buf, word);
diff --git a/lldb/tools/yaml2macho-core/Utility.cpp b/lldb/tools/yaml2macho-core/Utility.cpp
index 2414c2f039323..c56c8403b71c1 100644
--- a/lldb/tools/yaml2macho-core/Utility.cpp
+++ b/lldb/tools/yaml2macho-core/Utility.cpp
@@ -20,3 +20,9 @@ void add_uint32(std::vector<uint8_t> &buf, uint32_t val) {
   for (int i = 0; i < 4; i++)
     buf.push_back(*p++);
 }
+
+void add_uint16(std::vector<uint8_t> &buf, uint16_t val) {
+  uint8_t *p = reinterpret_cast<uint8_t *>(&val);
+  for (int i = 0; i < 2; i++)
+    buf.push_back(*p++);
+}
diff --git a/lldb/tools/yaml2macho-core/Utility.h b/lldb/tools/yaml2macho-core/Utility.h
index ff05858c4dee2..e20fb7c8d5756 100644
--- a/lldb/tools/yaml2macho-core/Utility.h
+++ b/lldb/tools/yaml2macho-core/Utility.h
@@ -14,5 +14,6 @@
 
 void add_uint64(std::vector<uint8_t> &buf, uint64_t val);
 void add_uint32(std::vector<uint8_t> &buf, uint32_t val);
+void add_uint16(std::vector<uint8_t> &buf, uint16_t val);
 
 #endif



More information about the lldb-commits mailing list