1 //===-- UnwindAssembly-x86.cpp ----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "UnwindAssembly-x86.h" 11 #include "x86AssemblyInspectionEngine.h" 12 13 #include "llvm-c/Disassembler.h" 14 #include "llvm/ADT/STLExtras.h" 15 #include "llvm/Support/TargetSelect.h" 16 17 #include "lldb/Core/Address.h" 18 #include "lldb/Core/PluginManager.h" 19 #include "lldb/Symbol/UnwindPlan.h" 20 #include "lldb/Target/ABI.h" 21 #include "lldb/Target/ExecutionContext.h" 22 #include "lldb/Target/Process.h" 23 #include "lldb/Target/RegisterContext.h" 24 #include "lldb/Target/RegisterNumber.h" 25 #include "lldb/Target/Target.h" 26 #include "lldb/Target/Thread.h" 27 #include "lldb/Target/UnwindAssembly.h" 28 #include "lldb/Utility/ArchSpec.h" 29 #include "lldb/Utility/Status.h" 30 31 using namespace lldb; 32 using namespace lldb_private; 33 34 //----------------------------------------------------------------------------------------------- 35 // UnwindAssemblyParser_x86 method definitions 36 //----------------------------------------------------------------------------------------------- 37 38 UnwindAssembly_x86::UnwindAssembly_x86(const ArchSpec &arch) 39 : lldb_private::UnwindAssembly(arch), 40 m_assembly_inspection_engine(new x86AssemblyInspectionEngine(arch)) {} 41 42 UnwindAssembly_x86::~UnwindAssembly_x86() { 43 delete m_assembly_inspection_engine; 44 } 45 46 bool UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly( 47 AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) { 48 if (!func.GetBaseAddress().IsValid() || func.GetByteSize() == 0) 49 return false; 50 if (m_assembly_inspection_engine == nullptr) 51 return false; 52 ProcessSP process_sp(thread.GetProcess()); 53 if (process_sp.get() == nullptr) 54 return false; 55 const bool prefer_file_cache = true; 56 std::vector<uint8_t> function_text(func.GetByteSize()); 57 Status error; 58 if (process_sp->GetTarget().ReadMemory( 59 func.GetBaseAddress(), prefer_file_cache, function_text.data(), 60 func.GetByteSize(), error) == func.GetByteSize()) { 61 RegisterContextSP reg_ctx(thread.GetRegisterContext()); 62 m_assembly_inspection_engine->Initialize(reg_ctx); 63 return m_assembly_inspection_engine->GetNonCallSiteUnwindPlanFromAssembly( 64 function_text.data(), func.GetByteSize(), func, unwind_plan); 65 } 66 return false; 67 } 68 69 bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite( 70 AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) { 71 bool do_augment_unwindplan = true; 72 73 UnwindPlan::RowSP first_row = unwind_plan.GetRowForFunctionOffset(0); 74 UnwindPlan::RowSP last_row = unwind_plan.GetRowForFunctionOffset(-1); 75 76 int wordsize = 8; 77 ProcessSP process_sp(thread.GetProcess()); 78 if (process_sp.get() == nullptr) 79 return false; 80 81 wordsize = process_sp->GetTarget().GetArchitecture().GetAddressByteSize(); 82 83 RegisterNumber sp_regnum(thread, eRegisterKindGeneric, 84 LLDB_REGNUM_GENERIC_SP); 85 RegisterNumber pc_regnum(thread, eRegisterKindGeneric, 86 LLDB_REGNUM_GENERIC_PC); 87 88 // Does this UnwindPlan describe the prologue? I want to see that the CFA is 89 // set in terms of the stack pointer plus an offset, and I want to see that 90 // rip is retrieved at the CFA-wordsize. If there is no description of the 91 // prologue, don't try to augment this eh_frame unwinder code, fall back to 92 // assembly parsing instead. 93 94 if (first_row->GetCFAValue().GetValueType() != 95 UnwindPlan::Row::FAValue::isRegisterPlusOffset || 96 RegisterNumber(thread, unwind_plan.GetRegisterKind(), 97 first_row->GetCFAValue().GetRegisterNumber()) != 98 sp_regnum || 99 first_row->GetCFAValue().GetOffset() != wordsize) { 100 return false; 101 } 102 UnwindPlan::Row::RegisterLocation first_row_pc_loc; 103 if (first_row->GetRegisterInfo( 104 pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()), 105 first_row_pc_loc) == false || 106 first_row_pc_loc.IsAtCFAPlusOffset() == false || 107 first_row_pc_loc.GetOffset() != -wordsize) { 108 return false; 109 } 110 111 // It looks like the prologue is described. Is the epilogue described? If it 112 // is, no need to do any augmentation. 113 114 if (first_row != last_row && 115 first_row->GetOffset() != last_row->GetOffset()) { 116 // The first & last row have the same CFA register and the same CFA offset 117 // value and the CFA register is esp/rsp (the stack pointer). 118 119 // We're checking that both of them have an unwind rule like "CFA=esp+4" or 120 // CFA+rsp+8". 121 122 if (first_row->GetCFAValue().GetValueType() == 123 last_row->GetCFAValue().GetValueType() && 124 first_row->GetCFAValue().GetRegisterNumber() == 125 last_row->GetCFAValue().GetRegisterNumber() && 126 first_row->GetCFAValue().GetOffset() == 127 last_row->GetCFAValue().GetOffset()) { 128 // Get the register locations for eip/rip from the first & last rows. Are 129 // they both CFA plus an offset? Is it the same offset? 130 131 UnwindPlan::Row::RegisterLocation last_row_pc_loc; 132 if (last_row->GetRegisterInfo( 133 pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()), 134 last_row_pc_loc)) { 135 if (last_row_pc_loc.IsAtCFAPlusOffset() && 136 first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset()) { 137 138 // One last sanity check: Is the unwind rule for getting the caller 139 // pc value "deref the CFA-4" or "deref the CFA-8"? 140 141 // If so, we have an UnwindPlan that already describes the epilogue 142 // and we don't need to modify it at all. 143 144 if (first_row_pc_loc.GetOffset() == -wordsize) { 145 do_augment_unwindplan = false; 146 } 147 } 148 } 149 } 150 } 151 152 if (do_augment_unwindplan) { 153 if (!func.GetBaseAddress().IsValid() || func.GetByteSize() == 0) 154 return false; 155 if (m_assembly_inspection_engine == nullptr) 156 return false; 157 const bool prefer_file_cache = true; 158 std::vector<uint8_t> function_text(func.GetByteSize()); 159 Status error; 160 if (process_sp->GetTarget().ReadMemory( 161 func.GetBaseAddress(), prefer_file_cache, function_text.data(), 162 func.GetByteSize(), error) == func.GetByteSize()) { 163 RegisterContextSP reg_ctx(thread.GetRegisterContext()); 164 m_assembly_inspection_engine->Initialize(reg_ctx); 165 return m_assembly_inspection_engine->AugmentUnwindPlanFromCallSite( 166 function_text.data(), func.GetByteSize(), func, unwind_plan, reg_ctx); 167 } 168 } 169 170 return false; 171 } 172 173 bool UnwindAssembly_x86::GetFastUnwindPlan(AddressRange &func, Thread &thread, 174 UnwindPlan &unwind_plan) { 175 // if prologue is 176 // 55 pushl %ebp 177 // 89 e5 movl %esp, %ebp 178 // or 179 // 55 pushq %rbp 180 // 48 89 e5 movq %rsp, %rbp 181 182 // We should pull in the ABI architecture default unwind plan and return that 183 184 llvm::SmallVector<uint8_t, 4> opcode_data; 185 186 ProcessSP process_sp = thread.GetProcess(); 187 if (process_sp) { 188 Target &target(process_sp->GetTarget()); 189 const bool prefer_file_cache = true; 190 Status error; 191 if (target.ReadMemory(func.GetBaseAddress(), prefer_file_cache, 192 opcode_data.data(), 4, error) == 4) { 193 uint8_t i386_push_mov[] = {0x55, 0x89, 0xe5}; 194 uint8_t x86_64_push_mov[] = {0x55, 0x48, 0x89, 0xe5}; 195 196 if (memcmp(opcode_data.data(), i386_push_mov, sizeof(i386_push_mov)) == 197 0 || 198 memcmp(opcode_data.data(), x86_64_push_mov, 199 sizeof(x86_64_push_mov)) == 0) { 200 ABISP abi_sp = process_sp->GetABI(); 201 if (abi_sp) { 202 return abi_sp->CreateDefaultUnwindPlan(unwind_plan); 203 } 204 } 205 } 206 } 207 return false; 208 } 209 210 bool UnwindAssembly_x86::FirstNonPrologueInsn( 211 AddressRange &func, const ExecutionContext &exe_ctx, 212 Address &first_non_prologue_insn) { 213 214 if (!func.GetBaseAddress().IsValid()) 215 return false; 216 217 Target *target = exe_ctx.GetTargetPtr(); 218 if (target == nullptr) 219 return false; 220 221 if (m_assembly_inspection_engine == nullptr) 222 return false; 223 224 const bool prefer_file_cache = true; 225 std::vector<uint8_t> function_text(func.GetByteSize()); 226 Status error; 227 if (target->ReadMemory(func.GetBaseAddress(), prefer_file_cache, 228 function_text.data(), func.GetByteSize(), 229 error) == func.GetByteSize()) { 230 size_t offset; 231 if (m_assembly_inspection_engine->FindFirstNonPrologueInstruction( 232 function_text.data(), func.GetByteSize(), offset)) { 233 first_non_prologue_insn = func.GetBaseAddress(); 234 first_non_prologue_insn.Slide(offset); 235 } 236 return true; 237 } 238 return false; 239 } 240 241 UnwindAssembly *UnwindAssembly_x86::CreateInstance(const ArchSpec &arch) { 242 const llvm::Triple::ArchType cpu = arch.GetMachine(); 243 if (cpu == llvm::Triple::x86 || cpu == llvm::Triple::x86_64) 244 return new UnwindAssembly_x86(arch); 245 return NULL; 246 } 247 248 //------------------------------------------------------------------ 249 // PluginInterface protocol in UnwindAssemblyParser_x86 250 //------------------------------------------------------------------ 251 252 ConstString UnwindAssembly_x86::GetPluginName() { 253 return GetPluginNameStatic(); 254 } 255 256 uint32_t UnwindAssembly_x86::GetPluginVersion() { return 1; } 257 258 void UnwindAssembly_x86::Initialize() { 259 PluginManager::RegisterPlugin(GetPluginNameStatic(), 260 GetPluginDescriptionStatic(), CreateInstance); 261 } 262 263 void UnwindAssembly_x86::Terminate() { 264 PluginManager::UnregisterPlugin(CreateInstance); 265 } 266 267 lldb_private::ConstString UnwindAssembly_x86::GetPluginNameStatic() { 268 static ConstString g_name("x86"); 269 return g_name; 270 } 271 272 const char *UnwindAssembly_x86::GetPluginDescriptionStatic() { 273 return "i386 and x86_64 assembly language profiler plugin."; 274 } 275