jasonmolenda created this revision. jasonmolenda added a reviewer: tberghammer. jasonmolenda added subscribers: lldb-commits, clayborg. jasonmolenda set the repository for this revision to rL LLVM. Herald added subscribers: rengolin, aemerson.
This patch is to address a few issues I came up with when working on an armcc-generated ELF binary being run on a Cortex-M4 core with lldb. The first problem is that the elf binary comes in as a generic "arm" triple ("arm--") and the second is that we don't see to get any arm/thumb hints about the functions in this binary. This is a Cortex-M4 ("armv7em") so the instructions are always thumb. When lldb calls the instruction unwinder (FuncUnwinders::GetUnwindAssemblyProfiler) it gets the object file's arch and merges in the Target's arch via ArchSpec::MergeFrom. The object file has "arm--", the target has "armv7em-unknown-unknown". The changes to MergeFrom allow us to replace the "arm" cpu part of the triple with the Target's "armv7em". I wanted to centralize the "Cortex M0-M7 are always thumb" special knowledge a little better - we already had two examples where we were checking against specific core types (armv6m, armv7m, armv7em) in the disassembler. So I added a method to ArchSpec to check that. It's a very arm specific method name, but it seems a bit of an arm specific problem that we're trying to identify here. Down in the instruction emulation I use the ArchSpec method to make sure we don't try to emulate anything as arm because we're missing the arm/thumb hints from the ObjectFile. I imagine at some point I'll want to do something in SysV-Arm ABI plugin for the DefaultUnwindPlan to say that if this core is always running thumb instructions, the frame pointer is r7 for instance. That default UnwindPlan which uses the arm r11 as a frame pointer is a problem for the unwinder's behavior in a real mixed arm/thumb environment - we sidestep it inside Apple be using r7 as the frame pointer for both types of code. Tamas, I put you as the reviewer because this is closest to what you work on regularly. Please let me know what you think when you have a chance. Repository: rL LLVM http://reviews.llvm.org/D13578 Files: include/lldb/Core/ArchSpec.h source/Core/ArchSpec.cpp source/Core/Disassembler.cpp source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
Index: source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp =================================================================== --- source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -12992,8 +12992,10 @@ { if (EmulateInstruction::SetInstruction (insn_opcode, inst_addr, target)) { - if (m_arch.GetTriple().getArch() == llvm::Triple::thumb) + if (m_arch.GetTriple().getArch() == llvm::Triple::thumb || m_arch.IsAlwaysThumbInstructions ()) + { m_opcode_mode = eModeThumb; + } else { AddressClass addr_class = inst_addr.GetAddressClass(); @@ -13028,7 +13030,7 @@ read_inst_context.type = eContextReadOpcode; read_inst_context.SetNoArgs (); - if (m_opcode_cpsr & MASK_CPSR_T) + if (m_opcode_cpsr & MASK_CPSR_T || m_arch.IsAlwaysThumbInstructions()) { m_opcode_mode = eModeThumb; uint32_t thumb_opcode = MemARead(read_inst_context, pc, 2, 0, &success); @@ -13657,19 +13659,17 @@ } test_opcode = value_sp->GetUInt64Value (); - if (arch.GetTriple().getArch() == llvm::Triple::arm) - { - m_opcode_mode = eModeARM; - m_opcode.SetOpcode32 (test_opcode, GetByteOrder()); - } - else if (arch.GetTriple().getArch() == llvm::Triple::thumb) + if (arch.GetTriple().getArch() == llvm::Triple::thumb || arch.IsAlwaysThumbInstructions ()) { m_opcode_mode = eModeThumb; if (test_opcode < 0x10000) m_opcode.SetOpcode16 (test_opcode, GetByteOrder()); else m_opcode.SetOpcode32 (test_opcode, GetByteOrder()); - + } else if (arch.GetTriple().getArch() == llvm::Triple::arm) + { + m_opcode_mode = eModeARM; + m_opcode.SetOpcode32 (test_opcode, GetByteOrder()); } else { Index: source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp =================================================================== --- source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp @@ -673,18 +673,8 @@ const char *triple_str = triple.getTriple().c_str(); - // v. https://en.wikipedia.org/wiki/ARM_Cortex-M#Silicon_customization - // - // Cortex-M3 devices (e.g. armv7m) can only execute thumb (T2) instructions, - // so hardcode the primary disassembler to thumb mode. Same for Cortex-M4 (armv7em). - // - // Handle the Cortex-M0 (armv6m) the same; the ISA is a subset of the T and T32 - // instructions defined in ARMv7-A. - - if ((triple.getArch() == llvm::Triple::arm || triple.getArch() == llvm::Triple::thumb) - && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m - || arch.GetCore() == ArchSpec::Core::eCore_arm_armv7em - || arch.GetCore() == ArchSpec::Core::eCore_arm_armv6m)) + // ARM Cortex M0-M7 devices only execute thumb instructions + if (arch.IsAlwaysThumbInstructions ()) { triple_str = thumb_arch.GetTriple().getTriple().c_str(); } Index: source/Core/Disassembler.cpp =================================================================== --- source/Core/Disassembler.cpp +++ source/Core/Disassembler.cpp @@ -1270,10 +1270,7 @@ // If this is an arm variant that can only include thumb (T16, T32) // instructions, force the arch triple to be "thumbv.." instead of // "armv..." - if ((arch.GetTriple().getArch() == llvm::Triple::arm || arch.GetTriple().getArch() == llvm::Triple::thumb) - && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m - || arch.GetCore() == ArchSpec::Core::eCore_arm_armv7em - || arch.GetCore() == ArchSpec::Core::eCore_arm_armv6m)) + if (arch.IsAlwaysThumbInstructions()) { std::string thumb_arch_name (arch.GetTriple().getArchName().str()); // Replace "arm" with "thumb" so we get all thumb variants correct Index: source/Core/ArchSpec.cpp =================================================================== --- source/Core/ArchSpec.cpp +++ source/Core/ArchSpec.cpp @@ -850,6 +850,19 @@ GetTriple().setOS(other.GetTriple().getOS()); if (GetTriple().getArch() == llvm::Triple::UnknownArch) GetTriple().setArch(other.GetTriple().getArch()); + + // If this and other are both arm ArchSpecs and this ArchSpec is a generic "some kind of arm" + // spec but the other ArchSpec is a specific arm core, adopt the specific arm core. + if (GetTriple().getArch() == llvm::Triple::arm + && other.GetTriple().getArch() == llvm::Triple::arm + && IsCompatibleMatch (other) + && GetCore() == ArchSpec::eCore_arm_generic + && other.GetCore() != ArchSpec::eCore_arm_generic) + { + m_core = other.GetCore(); + CoreUpdated (true); + } + if (GetTriple().getEnvironment() == llvm::Triple::UnknownEnvironment) GetTriple().setEnvironment(other.GetTriple().getEnvironment()); } @@ -1444,3 +1457,22 @@ return StopInfoOverrideCallbackTypeARM; return NULL; } + +bool +ArchSpec::IsAlwaysThumbInstructions () const +{ + // v. https://en.wikipedia.org/wiki/ARM_Cortex-M#Silicon_customization + // Cortex-M0 - ARMv6-M - armv6m + // Cortex-M3 - ARMv7-M - armv7m + // Cortex-M4 - ARMv7E-M - armv7em + if (GetTriple().getArch() == llvm::Triple::arm || GetTriple().getArch() == llvm::Triple::thumb) + { + if (GetCore() == ArchSpec::Core::eCore_arm_armv6m + || GetCore() == ArchSpec::Core::eCore_arm_armv7m + || GetCore() == ArchSpec::Core::eCore_arm_armv7em) + { + return true; + } + } + return false; +} Index: include/lldb/Core/ArchSpec.h =================================================================== --- include/lldb/Core/ArchSpec.h +++ include/lldb/Core/ArchSpec.h @@ -581,6 +581,22 @@ m_flags = flags; } + //------------------------------------------------------------------ + /// Detect whether this architecture uses thumb code exclusively + /// + /// Some embedded ARM chips (e.g. the ARM Cortex M0-7 line) can + /// only execute the Thumb instructions, never Arm. We should normally + /// pick up arm/thumbness from their the processor status bits (cpsr/xpsr) + /// or hints on each function - but when doing bare-boards low level + /// debugging (especially common with these embedded processors), we may + /// not have those things easily accessible. + /// + /// @return true if this is an arm ArchSpec which can only execute Thumb + /// instructions + //------------------------------------------------------------------ + bool + IsAlwaysThumbInstructions () const; + protected: bool IsEqualTo (const ArchSpec& rhs, bool exact_match) const;
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits