[Lldb-commits] [lldb] [lldb] Support overriding the disassembly CPU & features (PR #115382)

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Fri Nov 8 09:33:02 PST 2024


https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/115382

>From b5947cfe8fd7702f801c91f48ca050a5c839a707 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 7 Nov 2024 14:08:50 -0800
Subject: [PATCH 1/4] [lldb] Support overriding the disassembly CPU & features

Add the ability to override the disassembly CPU and CPU features through
a target setting (`target.disassembly-cpu` and
`target.disassembly-features`) and a `disassemble` command option
(`--cpu` and `--features`).

This is especially relevant for architectures like RISC-V which relies
heavily on CPU extensions.

The majority of this patch is plumbing the options through. I recommend
looking at DisassemblerLLVMC and the test for the observable change in
behavior.
---
 lldb/include/lldb/Core/Disassembler.h         |  32 +--
 .../Interpreter/CommandOptionArgumentTable.h  |   2 +
 lldb/include/lldb/Target/Target.h             |   4 +
 lldb/include/lldb/lldb-enumerations.h         |   2 +
 lldb/include/lldb/lldb-private-interfaces.h   |   5 +-
 lldb/source/API/SBFunction.cpp                |   4 +-
 lldb/source/API/SBSymbol.cpp                  |   4 +-
 lldb/source/API/SBTarget.cpp                  |  13 +-
 .../Commands/CommandObjectDisassemble.cpp     |  38 ++-
 .../Commands/CommandObjectDisassemble.h       |  14 ++
 lldb/source/Commands/Options.td               |   4 +
 lldb/source/Core/Disassembler.cpp             |  42 ++--
 lldb/source/Core/DumpDataExtractor.cpp        |   7 +-
 lldb/source/Expression/IRExecutionUnit.cpp    |   6 +-
 .../Architecture/Mips/ArchitectureMips.cpp    |   2 +-
 .../Disassembler/LLVMC/DisassemblerLLVMC.cpp  | 120 ++++-----
 .../Disassembler/LLVMC/DisassemblerLLVMC.h    |   8 +-
 .../Windows-DYLD/DynamicLoaderWindowsDYLD.cpp |   2 +-
 .../Process/Utility/StopInfoMachException.cpp |   7 +-
 .../UnwindAssemblyInstEmulation.cpp           |   4 +-
 lldb/source/Symbol/Function.cpp               |   6 +-
 lldb/source/Symbol/Symbol.cpp                 |   6 +-
 lldb/source/Target/Process.cpp                |   5 +-
 lldb/source/Target/StackFrame.cpp             |  17 +-
 lldb/source/Target/Target.cpp                 |  14 ++
 lldb/source/Target/TargetProperties.td        |   6 +
 lldb/source/Target/ThreadPlanStepRange.cpp    |   6 +-
 lldb/source/Target/ThreadPlanTracer.cpp       |   5 +-
 lldb/source/Target/TraceDumper.cpp            |   6 +-
 .../command-disassemble-cpu-features.yaml     | 230 ++++++++++++++++++
 30 files changed, 478 insertions(+), 143 deletions(-)
 create mode 100644 lldb/test/Shell/Commands/command-disassemble-cpu-features.yaml

diff --git a/lldb/include/lldb/Core/Disassembler.h b/lldb/include/lldb/Core/Disassembler.h
index 21969aed03c209..e0ad4316e02497 100644
--- a/lldb/include/lldb/Core/Disassembler.h
+++ b/lldb/include/lldb/Core/Disassembler.h
@@ -409,35 +409,37 @@ class Disassembler : public std::enable_shared_from_this<Disassembler>,
   // flavor string gets set wrong. Instead, if you get a flavor string you
   // don't understand, use the default.  Folks who care to check can use the
   // FlavorValidForArchSpec method on the disassembler they got back.
-  static lldb::DisassemblerSP
-  FindPlugin(const ArchSpec &arch, const char *flavor, const char *plugin_name);
+  static lldb::DisassemblerSP FindPlugin(const ArchSpec &arch,
+                                         const char *flavor, const char *cpu,
+                                         const char *features,
+                                         const char *plugin_name);
 
   // This version will use the value in the Target settings if flavor is NULL;
-  static lldb::DisassemblerSP FindPluginForTarget(const Target &target,
-                                                  const ArchSpec &arch,
-                                                  const char *flavor,
-                                                  const char *plugin_name);
+  static lldb::DisassemblerSP
+  FindPluginForTarget(const Target &target, const ArchSpec &arch,
+                      const char *flavor, const char *cpu, const char *features,
+                      const char *plugin_name);
 
   struct Limit {
     enum { Bytes, Instructions } kind;
     lldb::addr_t value;
   };
 
-  static lldb::DisassemblerSP DisassembleRange(const ArchSpec &arch,
-                                               const char *plugin_name,
-                                               const char *flavor,
-                                               Target &target,
-                                               const AddressRange &disasm_range,
-                                               bool force_live_memory = false);
+  static lldb::DisassemblerSP
+  DisassembleRange(const ArchSpec &arch, const char *plugin_name,
+                   const char *flavor, const char *cpu, const char *features,
+                   Target &target, const AddressRange &disasm_range,
+                   bool force_live_memory = false);
 
   static lldb::DisassemblerSP
   DisassembleBytes(const ArchSpec &arch, const char *plugin_name,
-                   const char *flavor, const Address &start, const void *bytes,
-                   size_t length, uint32_t max_num_instructions,
-                   bool data_from_file);
+                   const char *flavor, const char *cpu, const char *features,
+                   const Address &start, const void *bytes, size_t length,
+                   uint32_t max_num_instructions, bool data_from_file);
 
   static bool Disassemble(Debugger &debugger, const ArchSpec &arch,
                           const char *plugin_name, const char *flavor,
+                          const char *cpu, const char *features,
                           const ExecutionContext &exe_ctx, const Address &start,
                           Limit limit, bool mixed_source_and_assembly,
                           uint32_t num_mixed_context_lines, uint32_t options,
diff --git a/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h b/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
index b5e989633ea3fc..1875ff6a048d4c 100644
--- a/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
+++ b/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
@@ -312,6 +312,8 @@ static constexpr CommandObject::ArgumentTableEntry g_argument_table[] = {
     { lldb::eArgTypeRemotePath, "remote-path", lldb::CompletionType::eRemoteDiskFileCompletion, {}, { nullptr, false }, "A path on the system managed by the current platform." },
     { lldb::eArgTypeRemoteFilename, "remote-filename", lldb::CompletionType::eRemoteDiskFileCompletion, {}, { nullptr, false }, "A file on the system managed by the current platform." },
     { lldb::eArgTypeModule, "module", lldb::CompletionType::eModuleCompletion, {}, { nullptr, false }, "The name of a module loaded into the current target." },
+    { lldb::eArgTypeCPUName, "cpu-name", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of a CPU." },
+    { lldb::eArgTypeCPUFeatures, "cpu-features", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The CPU feature string." },
     // clang-format on
 };
 
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index cab21c29a7486f..f4ca5df44b7878 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -119,6 +119,10 @@ class TargetProperties : public Properties {
 
   const char *GetDisassemblyFlavor() const;
 
+  const char *GetDisassemblyCPU() const;
+
+  const char *GetDisassemblyFeatures() const;
+
   InlineStrategy GetInlineStrategy() const;
 
   RealpathPrefixes GetSourceRealpathPrefixes() const;
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 938f6e3abe8f2a..a9a66ea2662f39 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -655,6 +655,8 @@ enum CommandArgumentType {
   eArgTypeRemotePath,
   eArgTypeRemoteFilename,
   eArgTypeModule,
+  eArgTypeCPUName,
+  eArgTypeCPUFeatures,
   eArgTypeLastArg // Always keep this entry as the last entry in this
                   // enumeration!!
 };
diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h
index 5bac5cd3e86b59..d366dbd1d78329 100644
--- a/lldb/include/lldb/lldb-private-interfaces.h
+++ b/lldb/include/lldb/lldb-private-interfaces.h
@@ -29,8 +29,9 @@ typedef lldb::ABISP (*ABICreateInstance)(lldb::ProcessSP process_sp,
                                          const ArchSpec &arch);
 typedef std::unique_ptr<Architecture> (*ArchitectureCreateInstance)(
     const ArchSpec &arch);
-typedef lldb::DisassemblerSP (*DisassemblerCreateInstance)(const ArchSpec &arch,
-                                                           const char *flavor);
+typedef lldb::DisassemblerSP (*DisassemblerCreateInstance)(
+    const ArchSpec &arch, const char *flavor, const char *cpu,
+    const char *features);
 typedef DynamicLoader *(*DynamicLoaderCreateInstance)(Process *process,
                                                       bool force);
 typedef lldb::JITLoaderSP (*JITLoaderCreateInstance)(Process *process,
diff --git a/lldb/source/API/SBFunction.cpp b/lldb/source/API/SBFunction.cpp
index 6a97352fc2c2fd..c07d48fe5b499d 100644
--- a/lldb/source/API/SBFunction.cpp
+++ b/lldb/source/API/SBFunction.cpp
@@ -125,8 +125,8 @@ SBInstructionList SBFunction::GetInstructions(SBTarget target,
       lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
       const bool force_live_memory = true;
       sb_instructions.SetDisassembler(Disassembler::DisassembleRange(
-          module_sp->GetArchitecture(), nullptr, flavor, *target_sp,
-          m_opaque_ptr->GetAddressRange(), force_live_memory));
+          module_sp->GetArchitecture(), nullptr, flavor, nullptr, nullptr,
+          *target_sp, m_opaque_ptr->GetAddressRange(), force_live_memory));
     }
   }
   return sb_instructions;
diff --git a/lldb/source/API/SBSymbol.cpp b/lldb/source/API/SBSymbol.cpp
index 3f940538d1240a..90920060594143 100644
--- a/lldb/source/API/SBSymbol.cpp
+++ b/lldb/source/API/SBSymbol.cpp
@@ -126,8 +126,8 @@ SBInstructionList SBSymbol::GetInstructions(SBTarget target,
         AddressRange symbol_range(symbol_addr, m_opaque_ptr->GetByteSize());
         const bool force_live_memory = true;
         sb_instructions.SetDisassembler(Disassembler::DisassembleRange(
-            module_sp->GetArchitecture(), nullptr, flavor_string, *target_sp,
-            symbol_range, force_live_memory));
+            module_sp->GetArchitecture(), nullptr, flavor_string, nullptr,
+            nullptr, *target_sp, symbol_range, force_live_memory));
       }
     }
   }
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 28bdf47a34137a..ff752a519d951e 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -2013,8 +2013,9 @@ lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress base_addr,
                                 error, force_live_memory, &load_addr);
       const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
       sb_instructions.SetDisassembler(Disassembler::DisassembleBytes(
-          target_sp->GetArchitecture(), nullptr, flavor_string, *addr_ptr,
-          data.GetBytes(), bytes_read, count, data_from_file));
+          target_sp->GetArchitecture(), nullptr, nullptr, nullptr,
+          flavor_string, *addr_ptr, data.GetBytes(), bytes_read, count,
+          data_from_file));
     }
   }
 
@@ -2038,8 +2039,8 @@ lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress start_addr,
       AddressRange range(start_load_addr, size);
       const bool force_live_memory = true;
       sb_instructions.SetDisassembler(Disassembler::DisassembleRange(
-          target_sp->GetArchitecture(), nullptr, flavor_string, *target_sp,
-          range, force_live_memory));
+          target_sp->GetArchitecture(), nullptr, flavor_string, nullptr,
+          nullptr, *target_sp, range, force_live_memory));
     }
   }
   return sb_instructions;
@@ -2071,8 +2072,8 @@ SBTarget::GetInstructionsWithFlavor(lldb::SBAddress base_addr,
     const bool data_from_file = true;
 
     sb_instructions.SetDisassembler(Disassembler::DisassembleBytes(
-        target_sp->GetArchitecture(), nullptr, flavor_string, addr, buf, size,
-        UINT32_MAX, data_from_file));
+        target_sp->GetArchitecture(), nullptr, flavor_string, nullptr, nullptr,
+        addr, buf, size, UINT32_MAX, data_from_file));
   }
 
   return sb_instructions;
diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp
index 250f849ac04c55..6db4b2665bd84a 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.cpp
+++ b/lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -120,6 +120,14 @@ Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
     break;
   }
 
+  case 'X':
+    cpu_string = std::string(option_arg);
+    break;
+
+  case 'Y':
+    features_string = std::string(option_arg);
+    break;
+
   case 'r':
     raw = true;
     break;
@@ -176,20 +184,27 @@ void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
   Target *target =
       execution_context ? execution_context->GetTargetPtr() : nullptr;
 
-  // This is a hack till we get the ability to specify features based on
-  // architecture.  For now GetDisassemblyFlavor is really only valid for x86
-  // (and for the llvm assembler plugin, but I'm papering over that since that
-  // is the only disassembler plugin we have...
   if (target) {
+    // This is a hack till we get the ability to specify features based on
+    // architecture.  For now GetDisassemblyFlavor is really only valid for x86
+    // (and for the llvm assembler plugin, but I'm papering over that since that
+    // is the only disassembler plugin we have...
     if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 ||
         target->GetArchitecture().GetTriple().getArch() ==
             llvm::Triple::x86_64) {
       flavor_string.assign(target->GetDisassemblyFlavor());
-    } else
+    } else {
       flavor_string.assign("default");
-
-  } else
+    }
+    if (const char *cpu = target->GetDisassemblyCPU())
+      cpu_string.assign(cpu);
+    if (const char *features = target->GetDisassemblyFeatures())
+      features_string.assign(features);
+  } else {
     flavor_string.assign("default");
+    cpu_string.assign("default");
+    features_string.assign("default");
+  }
 
   arch.Clear();
   some_location_specified = false;
@@ -453,9 +468,11 @@ void CommandObjectDisassemble::DoExecute(Args &command,
 
   const char *plugin_name = m_options.GetPluginName();
   const char *flavor_string = m_options.GetFlavorString();
+  const char *cpu_string = m_options.GetCPUString();
+  const char *features_string = m_options.GetFeaturesString();
 
-  DisassemblerSP disassembler =
-      Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);
+  DisassemblerSP disassembler = Disassembler::FindPlugin(
+      m_options.arch, flavor_string, cpu_string, features_string, plugin_name);
 
   if (!disassembler) {
     if (plugin_name) {
@@ -524,7 +541,8 @@ void CommandObjectDisassemble::DoExecute(Args &command,
     }
     if (Disassembler::Disassemble(
             GetDebugger(), m_options.arch, plugin_name, flavor_string,
-            m_exe_ctx, cur_range.GetBaseAddress(), limit, m_options.show_mixed,
+            cpu_string, features_string, m_exe_ctx, cur_range.GetBaseAddress(),
+            limit, m_options.show_mixed,
             m_options.show_mixed ? m_options.num_lines_context : 0, options,
             result.GetOutputStream())) {
       result.SetStatus(eReturnStatusSuccessFinishResult);
diff --git a/lldb/source/Commands/CommandObjectDisassemble.h b/lldb/source/Commands/CommandObjectDisassemble.h
index 2e4d46dd0ec586..f9cba1e5ae9cb6 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.h
+++ b/lldb/source/Commands/CommandObjectDisassemble.h
@@ -42,6 +42,18 @@ class CommandObjectDisassemble : public CommandObjectParsed {
       return flavor_string.c_str();
     }
 
+    const char *GetCPUString() {
+      if (cpu_string.empty() || cpu_string == "default")
+        return nullptr;
+      return cpu_string.c_str();
+    }
+
+    const char *GetFeaturesString() {
+      if (features_string.empty() || features_string == "default")
+        return nullptr;
+      return features_string.c_str();
+    }
+
     Status OptionParsingFinished(ExecutionContext *execution_context) override;
 
     bool show_mixed; // Show mixed source/assembly
@@ -58,6 +70,8 @@ class CommandObjectDisassemble : public CommandObjectParsed {
     bool frame_line = false;
     std::string plugin_name;
     std::string flavor_string;
+    std::string cpu_string;
+    std::string features_string;
     ArchSpec arch;
     bool some_location_specified = false; // If no location was specified, we'll
                                           // select "at_pc".  This should be set
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 9d8d45d083eca4..777f8c36c4916c 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -324,6 +324,10 @@ let Command = "disassemble" in {
     Arg<"DisassemblyFlavor">, Desc<"Name of the disassembly flavor you want to "
     "use. Currently the only valid options are default, and for Intel "
     "architectures, att and intel.">;
+  def disassemble_options_cpu : Option<"cpu", "X">, Arg<"CPUName">,
+    Desc<"Override the CPU for disassembling.">;
+  def disassemble_options_features : Option<"features", "Y">, Arg<"CPUFeatures">,
+    Desc<"Specify additional CPU features for disassembling.">;
   def disassemble_options_arch : Option<"arch", "A">, Arg<"Architecture">,
     Desc<"Specify the architecture to use from cross disassembly.">;
   def disassemble_options_start_address : Option<"start-address", "s">,
diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp
index d071e3bfe4f77d..522a3ef2efc334 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -56,7 +56,8 @@ using namespace lldb;
 using namespace lldb_private;
 
 DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch,
-                                        const char *flavor,
+                                        const char *flavor, const char *cpu,
+                                        const char *features,
                                         const char *plugin_name) {
   LLDB_SCOPED_TIMERF("Disassembler::FindPlugin (arch = %s, plugin_name = %s)",
                      arch.GetArchitectureName(), plugin_name);
@@ -67,7 +68,7 @@ DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch,
     create_callback =
         PluginManager::GetDisassemblerCreateCallbackForPluginName(plugin_name);
     if (create_callback) {
-      if (auto disasm_sp = create_callback(arch, flavor))
+      if (auto disasm_sp = create_callback(arch, flavor, cpu, features))
         return disasm_sp;
     }
   } else {
@@ -75,18 +76,17 @@ DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch,
          (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(
               idx)) != nullptr;
          ++idx) {
-      if (auto disasm_sp = create_callback(arch, flavor))
+      if (auto disasm_sp = create_callback(arch, flavor, cpu, features))
         return disasm_sp;
     }
   }
   return DisassemblerSP();
 }
 
-DisassemblerSP Disassembler::FindPluginForTarget(const Target &target,
-                                                 const ArchSpec &arch,
-                                                 const char *flavor,
-                                                 const char *plugin_name) {
-  if (flavor == nullptr) {
+DisassemblerSP Disassembler::FindPluginForTarget(
+    const Target &target, const ArchSpec &arch, const char *flavor,
+    const char *cpu, const char *features, const char *plugin_name) {
+  if (!flavor) {
     // FIXME - we don't have the mechanism in place to do per-architecture
     // settings.  But since we know that for now we only support flavors on x86
     // & x86_64,
@@ -94,7 +94,12 @@ DisassemblerSP Disassembler::FindPluginForTarget(const Target &target,
         arch.GetTriple().getArch() == llvm::Triple::x86_64)
       flavor = target.GetDisassemblyFlavor();
   }
-  return FindPlugin(arch, flavor, plugin_name);
+  if (!cpu)
+    cpu = target.GetDisassemblyCPU();
+  if (!features)
+    features = target.GetDisassemblyFeatures();
+
+  return FindPlugin(arch, flavor, cpu, features, plugin_name);
 }
 
 static Address ResolveAddress(Target &target, const Address &addr) {
@@ -117,15 +122,16 @@ static Address ResolveAddress(Target &target, const Address &addr) {
 
 lldb::DisassemblerSP Disassembler::DisassembleRange(
     const ArchSpec &arch, const char *plugin_name, const char *flavor,
-    Target &target, const AddressRange &range, bool force_live_memory) {
+    const char *cpu, const char *features, Target &target,
+    const AddressRange &range, bool force_live_memory) {
   if (range.GetByteSize() <= 0)
     return {};
 
   if (!range.GetBaseAddress().IsValid())
     return {};
 
-  lldb::DisassemblerSP disasm_sp =
-      Disassembler::FindPluginForTarget(target, arch, flavor, plugin_name);
+  lldb::DisassemblerSP disasm_sp = Disassembler::FindPluginForTarget(
+      target, arch, flavor, cpu, features, plugin_name);
 
   if (!disasm_sp)
     return {};
@@ -141,14 +147,15 @@ lldb::DisassemblerSP Disassembler::DisassembleRange(
 
 lldb::DisassemblerSP
 Disassembler::DisassembleBytes(const ArchSpec &arch, const char *plugin_name,
-                               const char *flavor, const Address &start,
+                               const char *flavor, const char *cpu,
+                               const char *features, const Address &start,
                                const void *src, size_t src_len,
                                uint32_t num_instructions, bool data_from_file) {
   if (!src)
     return {};
 
   lldb::DisassemblerSP disasm_sp =
-      Disassembler::FindPlugin(arch, flavor, plugin_name);
+      Disassembler::FindPlugin(arch, flavor, cpu, features, plugin_name);
 
   if (!disasm_sp)
     return {};
@@ -163,6 +170,7 @@ Disassembler::DisassembleBytes(const ArchSpec &arch, const char *plugin_name,
 
 bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
                                const char *plugin_name, const char *flavor,
+                               const char *cpu, const char *features,
                                const ExecutionContext &exe_ctx,
                                const Address &address, Limit limit,
                                bool mixed_source_and_assembly,
@@ -172,7 +180,7 @@ bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
     return false;
 
   lldb::DisassemblerSP disasm_sp(Disassembler::FindPluginForTarget(
-      exe_ctx.GetTargetRef(), arch, flavor, plugin_name));
+      exe_ctx.GetTargetRef(), arch, flavor, cpu, features, plugin_name));
   if (!disasm_sp)
     return false;
 
@@ -559,8 +567,8 @@ bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
     if (limit.value == 0)
       limit.value = DEFAULT_DISASM_BYTE_SIZE;
 
-    return Disassemble(debugger, arch, nullptr, nullptr, frame,
-                       range.GetBaseAddress(), limit, false, 0, 0, strm);
+    return Disassemble(debugger, arch, nullptr, nullptr, nullptr, nullptr,
+                       frame, range.GetBaseAddress(), limit, false, 0, 0, strm);
 }
 
 Instruction::Instruction(const Address &address, AddressClass addr_class)
diff --git a/lldb/source/Core/DumpDataExtractor.cpp b/lldb/source/Core/DumpDataExtractor.cpp
index 826edd7bab046e..565ee3a0ae40a4 100644
--- a/lldb/source/Core/DumpDataExtractor.cpp
+++ b/lldb/source/Core/DumpDataExtractor.cpp
@@ -128,9 +128,10 @@ static lldb::offset_t DumpInstructions(const DataExtractor &DE, Stream *s,
   if (exe_scope)
     target_sp = exe_scope->CalculateTarget();
   if (target_sp) {
-    DisassemblerSP disassembler_sp(
-        Disassembler::FindPlugin(target_sp->GetArchitecture(),
-                                 target_sp->GetDisassemblyFlavor(), nullptr));
+    DisassemblerSP disassembler_sp(Disassembler::FindPlugin(
+        target_sp->GetArchitecture(), target_sp->GetDisassemblyFlavor(),
+        target_sp->GetDisassemblyCPU(), target_sp->GetDisassemblyFeatures(),
+        nullptr));
     if (disassembler_sp) {
       lldb::addr_t addr = base_addr + start_offset;
       lldb_private::Address so_addr;
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 7bee183d2ff227..9158b43b1c5c0d 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -167,8 +167,10 @@ Status IRExecutionUnit::DisassembleFunction(Stream &stream,
 
   const char *plugin_name = nullptr;
   const char *flavor_string = nullptr;
-  lldb::DisassemblerSP disassembler_sp =
-      Disassembler::FindPlugin(arch, flavor_string, plugin_name);
+  const char *cpu_string = nullptr;
+  const char *features_string = nullptr;
+  lldb::DisassemblerSP disassembler_sp = Disassembler::FindPlugin(
+      arch, flavor_string, cpu_string, features_string, plugin_name);
 
   if (!disassembler_sp) {
     ret = Status::FromErrorStringWithFormat(
diff --git a/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp b/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp
index a9f2e7af601db9..27ba10524141ed 100644
--- a/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp
+++ b/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp
@@ -150,7 +150,7 @@ Instruction *ArchitectureMips::GetInstructionAtAddress(
 
   // Create Disassembler Instance
   lldb::DisassemblerSP disasm_sp(
-    Disassembler::FindPlugin(m_arch, nullptr, nullptr));
+      Disassembler::FindPlugin(m_arch, nullptr, nullptr, nullptr, nullptr));
 
   InstructionList instruction_list;
   InstructionSP prev_insn;
diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
index 31edd8d46c444e..e108e92fcca4ce 100644
--- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
@@ -1439,7 +1439,9 @@ bool DisassemblerLLVMC::MCDisasmInstance::IsAuthenticated(
 }
 
 DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch,
-                                     const char *flavor_string)
+                                     const char *flavor_string,
+                                     const char *cpu_string,
+                                     const char *features_string)
     : Disassembler(arch, flavor_string), m_exe_ctx(nullptr), m_inst(nullptr),
       m_data_from_file(false), m_adrp_address(LLDB_INVALID_ADDRESS),
       m_adrp_insn() {
@@ -1447,6 +1449,7 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch,
     m_flavor.assign("default");
   }
 
+  const bool cpu_or_features_overriden = cpu_string || features_string;
   unsigned flavor = ~0U;
   llvm::Triple triple = arch.GetTriple();
 
@@ -1483,64 +1486,68 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch,
       triple.getSubArch() == llvm::Triple::NoSubArch)
     triple.setArchName("armv9.3a");
 
-  std::string features_str;
+  std::string features_str =
+      features_string ? std::string(features_string) : "";
   const char *triple_str = triple.getTriple().c_str();
 
   // ARM Cortex M0-M7 devices only execute thumb instructions
   if (arch.IsAlwaysThumbInstructions()) {
     triple_str = thumb_arch.GetTriple().getTriple().c_str();
-    features_str += "+fp-armv8,";
+    if (!features_string)
+      features_str += "+fp-armv8,";
   }
 
-  const char *cpu = "";
+  const char *cpu = cpu_string;
 
-  switch (arch.GetCore()) {
-  case ArchSpec::eCore_mips32:
-  case ArchSpec::eCore_mips32el:
-    cpu = "mips32";
-    break;
-  case ArchSpec::eCore_mips32r2:
-  case ArchSpec::eCore_mips32r2el:
-    cpu = "mips32r2";
-    break;
-  case ArchSpec::eCore_mips32r3:
-  case ArchSpec::eCore_mips32r3el:
-    cpu = "mips32r3";
-    break;
-  case ArchSpec::eCore_mips32r5:
-  case ArchSpec::eCore_mips32r5el:
-    cpu = "mips32r5";
-    break;
-  case ArchSpec::eCore_mips32r6:
-  case ArchSpec::eCore_mips32r6el:
-    cpu = "mips32r6";
-    break;
-  case ArchSpec::eCore_mips64:
-  case ArchSpec::eCore_mips64el:
-    cpu = "mips64";
-    break;
-  case ArchSpec::eCore_mips64r2:
-  case ArchSpec::eCore_mips64r2el:
-    cpu = "mips64r2";
-    break;
-  case ArchSpec::eCore_mips64r3:
-  case ArchSpec::eCore_mips64r3el:
-    cpu = "mips64r3";
-    break;
-  case ArchSpec::eCore_mips64r5:
-  case ArchSpec::eCore_mips64r5el:
-    cpu = "mips64r5";
-    break;
-  case ArchSpec::eCore_mips64r6:
-  case ArchSpec::eCore_mips64r6el:
-    cpu = "mips64r6";
-    break;
-  default:
-    cpu = "";
-    break;
+  if (!cpu_or_features_overriden) {
+    switch (arch.GetCore()) {
+    case ArchSpec::eCore_mips32:
+    case ArchSpec::eCore_mips32el:
+      cpu = "mips32";
+      break;
+    case ArchSpec::eCore_mips32r2:
+    case ArchSpec::eCore_mips32r2el:
+      cpu = "mips32r2";
+      break;
+    case ArchSpec::eCore_mips32r3:
+    case ArchSpec::eCore_mips32r3el:
+      cpu = "mips32r3";
+      break;
+    case ArchSpec::eCore_mips32r5:
+    case ArchSpec::eCore_mips32r5el:
+      cpu = "mips32r5";
+      break;
+    case ArchSpec::eCore_mips32r6:
+    case ArchSpec::eCore_mips32r6el:
+      cpu = "mips32r6";
+      break;
+    case ArchSpec::eCore_mips64:
+    case ArchSpec::eCore_mips64el:
+      cpu = "mips64";
+      break;
+    case ArchSpec::eCore_mips64r2:
+    case ArchSpec::eCore_mips64r2el:
+      cpu = "mips64r2";
+      break;
+    case ArchSpec::eCore_mips64r3:
+    case ArchSpec::eCore_mips64r3el:
+      cpu = "mips64r3";
+      break;
+    case ArchSpec::eCore_mips64r5:
+    case ArchSpec::eCore_mips64r5el:
+      cpu = "mips64r5";
+      break;
+    case ArchSpec::eCore_mips64r6:
+    case ArchSpec::eCore_mips64r6el:
+      cpu = "mips64r6";
+      break;
+    default:
+      cpu = "";
+      break;
+    }
   }
 
-  if (arch.IsMIPS()) {
+  if (arch.IsMIPS() && !cpu_or_features_overriden) {
     uint32_t arch_flags = arch.GetFlags();
     if (arch_flags & ArchSpec::eMIPSAse_msa)
       features_str += "+msa,";
@@ -1550,15 +1557,15 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch,
       features_str += "+dspr2,";
   }
 
-  // If any AArch64 variant, enable latest ISA with all extensions.
-  if (triple.isAArch64()) {
+  // If any AArch64 variant, enable latest ISA with all extensions unless the
+  // CPU or features were overridden.
+  if (triple.isAArch64() && !cpu_or_features_overriden) {
     features_str += "+all,";
-
     if (triple.getVendor() == llvm::Triple::Apple)
       cpu = "apple-latest";
   }
 
-  if (triple.isRISCV()) {
+  if (triple.isRISCV() && !cpu_or_features_overriden) {
     uint32_t arch_flags = arch.GetFlags();
     if (arch_flags & ArchSpec::eRISCV_rvc)
       features_str += "+c,";
@@ -1614,9 +1621,12 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch,
 DisassemblerLLVMC::~DisassemblerLLVMC() = default;
 
 lldb::DisassemblerSP DisassemblerLLVMC::CreateInstance(const ArchSpec &arch,
-                                                       const char *flavor) {
+                                                       const char *flavor,
+                                                       const char *cpu,
+                                                       const char *features) {
   if (arch.GetTriple().getArch() != llvm::Triple::UnknownArch) {
-    auto disasm_sp = std::make_shared<DisassemblerLLVMC>(arch, flavor);
+    auto disasm_sp =
+        std::make_shared<DisassemblerLLVMC>(arch, flavor, cpu, features);
     if (disasm_sp && disasm_sp->IsValid())
       return disasm_sp;
   }
diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h
index 30c69de81dfc83..d6b3d70934989b 100644
--- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h
+++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h
@@ -22,8 +22,8 @@ class InstructionLLVMC;
 
 class DisassemblerLLVMC : public lldb_private::Disassembler {
 public:
-  DisassemblerLLVMC(const lldb_private::ArchSpec &arch,
-                    const char *flavor /* = NULL */);
+  DisassemblerLLVMC(const lldb_private::ArchSpec &arch, const char *flavor,
+                    const char *cpu, const char *features);
 
   ~DisassemblerLLVMC() override;
 
@@ -35,7 +35,9 @@ class DisassemblerLLVMC : public lldb_private::Disassembler {
   static llvm::StringRef GetPluginNameStatic() { return "llvm-mc"; }
 
   static lldb::DisassemblerSP CreateInstance(const lldb_private::ArchSpec &arch,
-                                             const char *flavor);
+                                             const char *flavor,
+                                             const char *cpu,
+                                             const char *features);
 
   size_t DecodeInstructions(const lldb_private::Address &base_addr,
                             const lldb_private::DataExtractor &data,
diff --git a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
index f044aa786806fc..348cf58d69243d 100644
--- a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
@@ -183,7 +183,7 @@ DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread,
   AddressRange range(pc, 2 * 15);
 
   DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
-      arch, nullptr, nullptr, m_process->GetTarget(), range);
+      arch, nullptr, nullptr, nullptr, nullptr, m_process->GetTarget(), range);
   if (!disassembler_sp) {
     return ThreadPlanSP();
   }
diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
index 25cee369d7ee3d..d08e99f4844de3 100644
--- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
+++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -48,10 +48,13 @@ GetPtrauthInstructionInfo(Target &target, const ArchSpec &arch,
                           const Address &at_addr) {
   const char *plugin_name = nullptr;
   const char *flavor = nullptr;
+  const char *cpu = nullptr;
+  const char *features = nullptr;
   AddressRange range_bounds(at_addr, 4);
   const bool prefer_file_cache = true;
-  DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
-      arch, plugin_name, flavor, target, range_bounds, prefer_file_cache);
+  DisassemblerSP disassembler_sp =
+      Disassembler::DisassembleRange(arch, plugin_name, flavor, cpu, features,
+                                     target, range_bounds, prefer_file_cache);
   if (!disassembler_sp)
     return std::nullopt;
 
diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
index 1a680d80a9d3d7..8a26d76b65d1b4 100644
--- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -70,8 +70,8 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
 
     const bool prefer_file_cache = true;
     DisassemblerSP disasm_sp(Disassembler::DisassembleBytes(
-        m_arch, nullptr, nullptr, range.GetBaseAddress(), opcode_data,
-        opcode_size, 99999, prefer_file_cache));
+        m_arch, nullptr, nullptr, nullptr, nullptr, range.GetBaseAddress(),
+        opcode_data, opcode_size, 99999, prefer_file_cache));
 
     Log *log = GetLog(LLDBLog::Unwind);
 
diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp
index 96d8322b43d843..04766e26674c8c 100644
--- a/lldb/source/Symbol/Function.cpp
+++ b/lldb/source/Symbol/Function.cpp
@@ -459,9 +459,9 @@ lldb::DisassemblerSP Function::GetInstructions(const ExecutionContext &exe_ctx,
                                                bool prefer_file_cache) {
   ModuleSP module_sp(GetAddressRange().GetBaseAddress().GetModule());
   if (module_sp && exe_ctx.HasTargetScope()) {
-    return Disassembler::DisassembleRange(module_sp->GetArchitecture(), nullptr,
-                                          flavor, exe_ctx.GetTargetRef(),
-                                          GetAddressRange(), !prefer_file_cache);
+    return Disassembler::DisassembleRange(
+        module_sp->GetArchitecture(), nullptr, nullptr, nullptr, flavor,
+        exe_ctx.GetTargetRef(), GetAddressRange(), !prefer_file_cache);
   }
   return lldb::DisassemblerSP();
 }
diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp
index 9b0042ffdb4bfe..4828de4fdfa377 100644
--- a/lldb/source/Symbol/Symbol.cpp
+++ b/lldb/source/Symbol/Symbol.cpp
@@ -591,9 +591,9 @@ lldb::DisassemblerSP Symbol::GetInstructions(const ExecutionContext &exe_ctx,
                                              bool prefer_file_cache) {
   ModuleSP module_sp(m_addr_range.GetBaseAddress().GetModule());
   if (module_sp && exe_ctx.HasTargetScope()) {
-    return Disassembler::DisassembleRange(module_sp->GetArchitecture(), nullptr,
-                                          flavor, exe_ctx.GetTargetRef(),
-                                          m_addr_range, !prefer_file_cache);
+    return Disassembler::DisassembleRange(
+        module_sp->GetArchitecture(), nullptr, flavor, nullptr, nullptr,
+        exe_ctx.GetTargetRef(), m_addr_range, !prefer_file_cache);
   }
   return lldb::DisassemblerSP();
 }
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index c009d17d3ba507..b99692b8a0bfd9 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -6144,8 +6144,11 @@ Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr,
 
   const char *plugin_name = nullptr;
   const char *flavor = nullptr;
+  const char *cpu = nullptr;
+  const char *features = nullptr;
   disassembler_sp = Disassembler::DisassembleRange(
-      target.GetArchitecture(), plugin_name, flavor, GetTarget(), range_bounds);
+      target.GetArchitecture(), plugin_name, flavor, cpu, features, GetTarget(),
+      range_bounds);
   if (disassembler_sp)
     insn_list = &disassembler_sp->GetInstructionList();
 
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 3761b867452c99..ef71fc6acb1703 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -1316,11 +1316,13 @@ lldb::ValueObjectSP StackFrame::GuessValueForAddress(lldb::addr_t addr) {
 
   const char *plugin_name = nullptr;
   const char *flavor = nullptr;
+  const char *cpu = nullptr;
+  const char *features = nullptr;
   const bool force_live_memory = true;
 
-  DisassemblerSP disassembler_sp =
-      Disassembler::DisassembleRange(target_arch, plugin_name, flavor,
-                                     *target_sp, pc_range, force_live_memory);
+  DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
+      target_arch, plugin_name, flavor, cpu, features, *target_sp, pc_range,
+      force_live_memory);
 
   if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize()) {
     return ValueObjectSP();
@@ -1697,10 +1699,12 @@ lldb::ValueObjectSP StackFrame::GuessValueForRegisterAndOffset(ConstString reg,
 
   const char *plugin_name = nullptr;
   const char *flavor = nullptr;
+  const char *cpu = nullptr;
+  const char *features = nullptr;
   const bool force_live_memory = true;
-  DisassemblerSP disassembler_sp =
-      Disassembler::DisassembleRange(target_arch, plugin_name, flavor,
-                                     *target_sp, pc_range, force_live_memory);
+  DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
+      target_arch, plugin_name, flavor, cpu, features, *target_sp, pc_range,
+      force_live_memory);
 
   if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize()) {
     return ValueObjectSP();
@@ -1966,6 +1970,7 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source,
             const bool mixed_source_and_assembly = false;
             Disassembler::Disassemble(
                 target->GetDebugger(), target_arch, plugin_name, flavor,
+                target->GetDisassemblyCPU(), target->GetDisassemblyFeatures(),
                 exe_ctx, GetFrameCodeAddress(),
                 {Disassembler::Limit::Instructions, disasm_lines},
                 mixed_source_and_assembly, 0,
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 242d2eaec2a15a..a788bad88b2977 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -4490,6 +4490,20 @@ const char *TargetProperties::GetDisassemblyFlavor() const {
   return return_value;
 }
 
+const char *TargetProperties::GetDisassemblyCPU() const {
+  const uint32_t idx = ePropertyDisassemblyCPU;
+  llvm::StringRef str = GetPropertyAtIndexAs<llvm::StringRef>(
+      idx, g_target_properties[idx].default_cstr_value);
+  return str.empty() ? nullptr : str.data();
+}
+
+const char *TargetProperties::GetDisassemblyFeatures() const {
+  const uint32_t idx = ePropertyDisassemblyFeatures;
+  llvm::StringRef str = GetPropertyAtIndexAs<llvm::StringRef>(
+      idx, g_target_properties[idx].default_cstr_value);
+  return str.empty() ? nullptr : str.data();
+}
+
 InlineStrategy TargetProperties::GetInlineStrategy() const {
   const uint32_t idx = ePropertyInlineStrategy;
   return GetPropertyAtIndexAs<InlineStrategy>(
diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td
index 00ad8dd2a9f7f9..d8d7e6353aad43 100644
--- a/lldb/source/Target/TargetProperties.td
+++ b/lldb/source/Target/TargetProperties.td
@@ -157,6 +157,12 @@ let Definition = "target" in {
     DefaultEnumValue<"eX86DisFlavorDefault">,
     EnumValues<"OptionEnumValues(g_x86_dis_flavor_value_types)">,
     Desc<"The default disassembly flavor to use for x86 or x86-64 targets.">;
+  def DisassemblyCPU: Property<"disassembly-cpu", "String">,
+    DefaultStringValue<"">,
+    Desc<"Override the CPU for disassembling. Takes the same values as the -mcpu compiler flag.">;
+  def DisassemblyFeatures: Property<"disassembly-features", "String">,
+    DefaultStringValue<"">,
+    Desc<"Specify additional CPU features for disassembling.">;
   def UseHexImmediates: Property<"use-hex-immediates", "Boolean">,
     DefaultTrue,
     Desc<"Show immediates in disassembly as hexadecimal.">;
diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp
index b64ce6f0dc9c28..de4cd5995f6953 100644
--- a/lldb/source/Target/ThreadPlanStepRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepRange.cpp
@@ -266,9 +266,11 @@ InstructionList *ThreadPlanStepRange::GetInstructionsForAddress(
         // Disassemble the address range given:
         const char *plugin_name = nullptr;
         const char *flavor = nullptr;
+        const char *cpu = nullptr;
+        const char *features = nullptr;
         m_instruction_ranges[i] = Disassembler::DisassembleRange(
-            GetTarget().GetArchitecture(), plugin_name, flavor, GetTarget(),
-            m_address_ranges[i]);
+            GetTarget().GetArchitecture(), plugin_name, flavor, cpu, features,
+            GetTarget(), m_address_ranges[i]);
       }
       if (!m_instruction_ranges[i])
         return nullptr;
diff --git a/lldb/source/Target/ThreadPlanTracer.cpp b/lldb/source/Target/ThreadPlanTracer.cpp
index acadda8f582f9d..ff9f49c6d4bb68 100644
--- a/lldb/source/Target/ThreadPlanTracer.cpp
+++ b/lldb/source/Target/ThreadPlanTracer.cpp
@@ -95,8 +95,9 @@ ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread)
 
 Disassembler *ThreadPlanAssemblyTracer::GetDisassembler() {
   if (!m_disassembler_sp)
-    m_disassembler_sp = Disassembler::FindPlugin(
-        m_process.GetTarget().GetArchitecture(), nullptr, nullptr);
+    m_disassembler_sp =
+        Disassembler::FindPlugin(m_process.GetTarget().GetArchitecture(),
+                                 nullptr, nullptr, nullptr, nullptr);
   return m_disassembler_sp.get();
 }
 
diff --git a/lldb/source/Target/TraceDumper.cpp b/lldb/source/Target/TraceDumper.cpp
index 4ef8efc1a67689..fa732fa87c5290 100644
--- a/lldb/source/Target/TraceDumper.cpp
+++ b/lldb/source/Target/TraceDumper.cpp
@@ -510,9 +510,9 @@ CalculateDisass(const TraceDumper::SymbolInfo &symbol_info,
   const ArchSpec arch = target.GetArchitecture();
   lldb_private::AddressRange range(symbol_info.address,
                                    arch.GetMaximumOpcodeByteSize());
-  DisassemblerSP disassembler =
-      Disassembler::DisassembleRange(arch, /*plugin_name*/ nullptr,
-                                     /*flavor*/ nullptr, target, range);
+  DisassemblerSP disassembler = Disassembler::DisassembleRange(
+      arch, /*plugin_name=*/nullptr,
+      /*flavor=*/nullptr, /*cpu=*/nullptr, /*features=*/nullptr, target, range);
   return std::make_tuple(
       disassembler,
       disassembler ? disassembler->GetInstructionList().GetInstructionAtAddress(
diff --git a/lldb/test/Shell/Commands/command-disassemble-cpu-features.yaml b/lldb/test/Shell/Commands/command-disassemble-cpu-features.yaml
new file mode 100644
index 00000000000000..199e78f4474ca6
--- /dev/null
+++ b/lldb/test/Shell/Commands/command-disassemble-cpu-features.yaml
@@ -0,0 +1,230 @@
+# REQUIRES: aarch64
+
+# RUN: yaml2obj %s -o %t.out
+
+# RUN: %lldb %t.out -b -o "disassemble -c 1 --cpu 'apple-a16' -n main" | FileCheck %s --check-prefix SUPPORTED
+# RUN: %lldb %t.out -b -o "disassemble -c 1 --cpu 'apple-a11' -n main" | FileCheck %s --check-prefix UNSUPPORTED
+# RUN: %lldb %t.out -b -o "disassemble -c 1 --cpu 'apple-a11' --features '+all' -n main" | FileCheck %s --check-prefix SUPPORTED
+
+# RUN: %lldb %t.out -b -o "settings set target.disassembly-cpu 'apple-a16'" -o "disassemble -c 1 -n main" | FileCheck %s --check-prefix SUPPORTED
+# RUN: %lldb %t.out -b -o "settings set target.disassembly-cpu 'apple-a11'" -o "disassemble -c 1 -n main" | FileCheck %s --check-prefix UNSUPPORTED
+# RUN: %lldb %t.out -b -o "settings set target.disassembly-cpu 'apple-a11'" -o "settings set target.disassembly-features '+all'" -o "disassemble -c 1 -n main" | FileCheck %s --check-prefix SUPPORTED
+
+# SUPPORTED: <+0>: pacibsp
+# UNSUPPORTED-NOT: <+0>: pacibsp
+
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x100000C
+  cpusubtype:      0x80000002
+  filetype:        0x2
+  ncmds:           17
+  sizeofcmds:      1056
+  flags:           0x200085
+  reserved:        0x0
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         72
+    segname:         __PAGEZERO
+    vmaddr:          0
+    vmsize:          4294967296
+    fileoff:         0
+    filesize:        0
+    maxprot:         0
+    initprot:        0
+    nsects:          0
+    flags:           0
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         392
+    segname:         __TEXT
+    vmaddr:          4294967296
+    vmsize:          16384
+    fileoff:         0
+    filesize:        16384
+    maxprot:         5
+    initprot:        5
+    nsects:          4
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x100000460
+        size:            36
+        offset:          0x460
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         7F2303D5FD7BBFA9FD03009100000090005012910400009400008052FD7BC1A8FF0F5FD6
+      - sectname:        __cstring
+        segname:         __TEXT
+        addr:            0x100000494
+        size:            3
+        offset:          0x494
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x2
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         '484900'
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         152
+    segname:         __DATA_CONST
+    vmaddr:          4294983680
+    vmsize:          16384
+    fileoff:         16384
+    filesize:        16384
+    maxprot:         3
+    initprot:        3
+    nsects:          1
+    flags:           16
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         72
+    segname:         __LINKEDIT
+    vmaddr:          4295000064
+    vmsize:          16384
+    fileoff:         32768
+    filesize:        664
+    maxprot:         1
+    initprot:        1
+    nsects:          0
+    flags:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          32920
+    nsyms:           3
+    stroff:          32976
+    strsize:         40
+  - cmd:             LC_DYSYMTAB
+    cmdsize:         80
+    ilocalsym:       0
+    nlocalsym:       0
+    iextdefsym:      0
+    nextdefsym:      2
+    iundefsym:       2
+    nundefsym:       1
+    tocoff:          0
+    ntoc:            0
+    modtaboff:       0
+    nmodtab:         0
+    extrefsymoff:    0
+    nextrefsyms:     0
+    indirectsymoff:  32968
+    nindirectsyms:   2
+    extreloff:       0
+    nextrel:         0
+    locreloff:       0
+    nlocrel:         0
+  - cmd:             LC_LOAD_DYLINKER
+    cmdsize:         32
+    name:            12
+    Content:         '/usr/lib/dyld'
+    ZeroPadBytes:    7
+  - cmd:             LC_UUID
+    cmdsize:         24
+    uuid:            CF3EBEFA-8D83-3C25-931A-5AF74AFE0B3A
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         32
+    platform:        1
+    minos:           983040
+    sdk:             983808
+    ntools:          1
+    Tools:
+      - tool:            3
+        version:         76153600
+  - cmd:             LC_SOURCE_VERSION
+    cmdsize:         16
+    version:         0
+  - cmd:             LC_MAIN
+    cmdsize:         24
+    entryoff:        1120
+    stacksize:       0
+  - cmd:             LC_LOAD_DYLIB
+    cmdsize:         56
+    dylib:
+      name:            24
+      timestamp:       2
+      current_version: 88539136
+      compatibility_version: 65536
+    Content:         '/usr/lib/libSystem.B.dylib'
+    ZeroPadBytes:    6
+  - cmd:             LC_FUNCTION_STARTS
+    cmdsize:         16
+    dataoff:         32912
+    datasize:        8
+  - cmd:             LC_DATA_IN_CODE
+    cmdsize:         16
+    dataoff:         32920
+    datasize:        0
+  - cmd:             LC_CODE_SIGNATURE
+    cmdsize:         16
+    dataoff:         33024
+    datasize:        408
+LinkEditData:
+  ExportTrie:
+    TerminalSize:    0
+    NodeOffset:      0
+    Name:            ''
+    Flags:           0x0
+    Address:         0x0
+    Other:           0x0
+    ImportName:      ''
+    Children:
+      - TerminalSize:    0
+        NodeOffset:      18
+        Name:            _
+        Flags:           0x0
+        Address:         0x0
+        Other:           0x0
+        ImportName:      ''
+        Children:
+          - TerminalSize:    2
+            NodeOffset:      9
+            Name:            _mh_execute_header
+            Flags:           0x0
+            Address:         0x0
+            Other:           0x0
+            ImportName:      ''
+          - TerminalSize:    3
+            NodeOffset:      13
+            Name:            main
+            Flags:           0x0
+            Address:         0x460
+            Other:           0x0
+            ImportName:      ''
+  NameList:
+    - n_strx:          2
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          16
+      n_value:         4294967296
+    - n_strx:          22
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968416
+    - n_strx:          28
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          256
+      n_value:         0
+  StringTable:
+    - ' '
+    - __mh_execute_header
+    - _main
+    - _puts
+    - ''
+    - ''
+    - ''
+    - ''
+    - ''
+    - ''
+  IndirectSymbols: [ 0x2, 0x2 ]
+  FunctionStarts:  [ 0x460 ]
+...

>From 584eba125a8263d3739a28739a8ca27a39a3107c Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 7 Nov 2024 16:29:10 -0800
Subject: [PATCH 2/4] Address Jason's feedback

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

diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td
index d8d7e6353aad43..4faf4c26b57011 100644
--- a/lldb/source/Target/TargetProperties.td
+++ b/lldb/source/Target/TargetProperties.td
@@ -159,7 +159,7 @@ let Definition = "target" in {
     Desc<"The default disassembly flavor to use for x86 or x86-64 targets.">;
   def DisassemblyCPU: Property<"disassembly-cpu", "String">,
     DefaultStringValue<"">,
-    Desc<"Override the CPU for disassembling. Takes the same values as the -mcpu compiler flag.">;
+    Desc<"Override the CPU for disassembling. Takes the same values as the -mcpu clang flag.">;
   def DisassemblyFeatures: Property<"disassembly-features", "String">,
     DefaultStringValue<"">,
     Desc<"Specify additional CPU features for disassembling.">;

>From 390624d7f63ac85f616e568dd7f8c38424b1cb6f Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 7 Nov 2024 16:29:56 -0800
Subject: [PATCH 3/4] Update unit test

---
 lldb/unittests/Disassembler/ARM/TestArm64Disassembly.cpp    | 5 +++--
 lldb/unittests/Disassembler/ARM/TestArmv7Disassembly.cpp    | 5 +++--
 .../Disassembler/RISCV/TestMCDisasmInstanceRISCV.cpp        | 6 +++---
 .../Disassembler/x86/TestGetControlFlowKindx86.cpp          | 6 +++---
 4 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/lldb/unittests/Disassembler/ARM/TestArm64Disassembly.cpp b/lldb/unittests/Disassembler/ARM/TestArm64Disassembly.cpp
index f89a918e3e54fa..dcca1a7ae959b3 100644
--- a/lldb/unittests/Disassembler/ARM/TestArm64Disassembly.cpp
+++ b/lldb/unittests/Disassembler/ARM/TestArm64Disassembly.cpp
@@ -56,8 +56,9 @@ TEST_F(TestArm64Disassembly, TestArmv81Instruction) {
 
   DisassemblerSP disass_sp;
   Address start_addr(0x100);
-  disass_sp = Disassembler::DisassembleBytes(arch, nullptr, nullptr, start_addr,
-                                 &data, sizeof (data), num_of_instructions, false);
+  disass_sp = Disassembler::DisassembleBytes(
+      arch, nullptr, nullptr, nullptr, nullptr, start_addr, &data, sizeof(data),
+      num_of_instructions, false);
 
   // If we failed to get a disassembler, we can assume it is because
   // the llvm we linked against was not built with the ARM target,
diff --git a/lldb/unittests/Disassembler/ARM/TestArmv7Disassembly.cpp b/lldb/unittests/Disassembler/ARM/TestArmv7Disassembly.cpp
index 047cba1db40821..00632cc57f005b 100644
--- a/lldb/unittests/Disassembler/ARM/TestArmv7Disassembly.cpp
+++ b/lldb/unittests/Disassembler/ARM/TestArmv7Disassembly.cpp
@@ -64,8 +64,9 @@ TEST_F(TestArmv7Disassembly, TestCortexFPDisass) {
 
   DisassemblerSP disass_sp;
   Address start_addr(0x100);
-  disass_sp = Disassembler::DisassembleBytes(arch, nullptr, nullptr, start_addr,
-                                 &data, sizeof (data), num_of_instructions, false);
+  disass_sp = Disassembler::DisassembleBytes(
+      arch, nullptr, nullptr, nullptr, nullptr, start_addr, &data, sizeof(data),
+      num_of_instructions, false);
 
   // If we failed to get a disassembler, we can assume it is because
   // the llvm we linked against was not built with the ARM target,
diff --git a/lldb/unittests/Disassembler/RISCV/TestMCDisasmInstanceRISCV.cpp b/lldb/unittests/Disassembler/RISCV/TestMCDisasmInstanceRISCV.cpp
index 2f2585a23d7624..8ec5d62a99ac57 100644
--- a/lldb/unittests/Disassembler/RISCV/TestMCDisasmInstanceRISCV.cpp
+++ b/lldb/unittests/Disassembler/RISCV/TestMCDisasmInstanceRISCV.cpp
@@ -56,9 +56,9 @@ TEST_F(TestMCDisasmInstanceRISCV, TestRISCV32Instruction) {
 
   DisassemblerSP disass_sp;
   Address start_addr(0x100);
-  disass_sp =
-      Disassembler::DisassembleBytes(arch, nullptr, nullptr, start_addr, &data,
-                                    sizeof (data), num_of_instructions, false);
+  disass_sp = Disassembler::DisassembleBytes(
+      arch, nullptr, nullptr, nullptr, nullptr, start_addr, &data, sizeof(data),
+      num_of_instructions, false);
 
   // If we failed to get a disassembler, we can assume it is because
   // the llvm we linked against was not built with the riscv target,
diff --git a/lldb/unittests/Disassembler/x86/TestGetControlFlowKindx86.cpp b/lldb/unittests/Disassembler/x86/TestGetControlFlowKindx86.cpp
index e9d5ae3f7b3cdb..4b62e5f747529c 100644
--- a/lldb/unittests/Disassembler/x86/TestGetControlFlowKindx86.cpp
+++ b/lldb/unittests/Disassembler/x86/TestGetControlFlowKindx86.cpp
@@ -124,9 +124,9 @@ TEST_F(TestGetControlFlowKindx86, TestX86_64Instruction) {
 
   DisassemblerSP disass_sp;
   Address start_addr(0x100);
-  disass_sp =
-      Disassembler::DisassembleBytes(arch, nullptr, nullptr, start_addr, &data,
-                                    sizeof (data), num_of_instructions, false);
+  disass_sp = Disassembler::DisassembleBytes(
+      arch, nullptr, nullptr, nullptr, nullptr, start_addr, &data, sizeof(data),
+      num_of_instructions, false);
 
   // If we failed to get a disassembler, we can assume it is because
   // the llvm we linked against was not built with the i386 target,

>From 3e3b00b96489ee0975c1b88fe3775642570ee123 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Fri, 8 Nov 2024 09:32:46 -0800
Subject: [PATCH 4/4] Honor the setting in the SBAPI

---
 lldb/source/API/SBFunction.cpp |  3 ++-
 lldb/source/API/SBSymbol.cpp   |  5 +++--
 lldb/source/API/SBTarget.cpp   | 14 ++++++++------
 3 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/lldb/source/API/SBFunction.cpp b/lldb/source/API/SBFunction.cpp
index c07d48fe5b499d..ac61220ec8736a 100644
--- a/lldb/source/API/SBFunction.cpp
+++ b/lldb/source/API/SBFunction.cpp
@@ -125,7 +125,8 @@ SBInstructionList SBFunction::GetInstructions(SBTarget target,
       lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
       const bool force_live_memory = true;
       sb_instructions.SetDisassembler(Disassembler::DisassembleRange(
-          module_sp->GetArchitecture(), nullptr, flavor, nullptr, nullptr,
+          module_sp->GetArchitecture(), nullptr, flavor,
+          target_sp->GetDisassemblyCPU(), target_sp->GetDisassemblyFeatures(),
           *target_sp, m_opaque_ptr->GetAddressRange(), force_live_memory));
     }
   }
diff --git a/lldb/source/API/SBSymbol.cpp b/lldb/source/API/SBSymbol.cpp
index 90920060594143..79477dd3a70fc6 100644
--- a/lldb/source/API/SBSymbol.cpp
+++ b/lldb/source/API/SBSymbol.cpp
@@ -126,8 +126,9 @@ SBInstructionList SBSymbol::GetInstructions(SBTarget target,
         AddressRange symbol_range(symbol_addr, m_opaque_ptr->GetByteSize());
         const bool force_live_memory = true;
         sb_instructions.SetDisassembler(Disassembler::DisassembleRange(
-            module_sp->GetArchitecture(), nullptr, flavor_string, nullptr,
-            nullptr, *target_sp, symbol_range, force_live_memory));
+            module_sp->GetArchitecture(), nullptr, flavor_string,
+            target_sp->GetDisassemblyCPU(), target_sp->GetDisassemblyFeatures(),
+            *target_sp, symbol_range, force_live_memory));
       }
     }
   }
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index ff752a519d951e..3c4c3d8d85292e 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -2013,9 +2013,9 @@ lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress base_addr,
                                 error, force_live_memory, &load_addr);
       const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
       sb_instructions.SetDisassembler(Disassembler::DisassembleBytes(
-          target_sp->GetArchitecture(), nullptr, nullptr, nullptr,
-          flavor_string, *addr_ptr, data.GetBytes(), bytes_read, count,
-          data_from_file));
+          target_sp->GetArchitecture(), nullptr, target_sp->GetDisassemblyCPU(),
+          target_sp->GetDisassemblyFeatures(), flavor_string, *addr_ptr,
+          data.GetBytes(), bytes_read, count, data_from_file));
     }
   }
 
@@ -2039,8 +2039,9 @@ lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress start_addr,
       AddressRange range(start_load_addr, size);
       const bool force_live_memory = true;
       sb_instructions.SetDisassembler(Disassembler::DisassembleRange(
-          target_sp->GetArchitecture(), nullptr, flavor_string, nullptr,
-          nullptr, *target_sp, range, force_live_memory));
+          target_sp->GetArchitecture(), nullptr, flavor_string,
+          target_sp->GetDisassemblyCPU(), target_sp->GetDisassemblyFeatures(),
+          *target_sp, range, force_live_memory));
     }
   }
   return sb_instructions;
@@ -2072,7 +2073,8 @@ SBTarget::GetInstructionsWithFlavor(lldb::SBAddress base_addr,
     const bool data_from_file = true;
 
     sb_instructions.SetDisassembler(Disassembler::DisassembleBytes(
-        target_sp->GetArchitecture(), nullptr, flavor_string, nullptr, nullptr,
+        target_sp->GetArchitecture(), nullptr, flavor_string,
+        target_sp->GetDisassemblyCPU(), target_sp->GetDisassemblyFeatures(),
         addr, buf, size, UINT32_MAX, data_from_file));
   }
 



More information about the lldb-commits mailing list