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/ArchSpec.h" 19 #include "lldb/Core/Error.h" 20 #include "lldb/Core/PluginManager.h" 21 #include "lldb/Symbol/UnwindPlan.h" 22 #include "lldb/Target/ABI.h" 23 #include "lldb/Target/ExecutionContext.h" 24 #include "lldb/Target/Process.h" 25 #include "lldb/Target/RegisterContext.h" 26 #include "lldb/Target/Target.h" 27 #include "lldb/Target/Thread.h" 28 #include "lldb/Target/UnwindAssembly.h" 29 #include "lldb/Utility/RegisterNumber.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 Error 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 90 // in terms of the stack pointer plus an offset, and I want to see that rip is 91 // retrieved at the CFA-wordsize. 92 // If there is no description of the prologue, don't try to augment this 93 // eh_frame 94 // unwinder code, fall back to assembly parsing instead. 95 96 if (first_row->GetCFAValue().GetValueType() != 97 UnwindPlan::Row::CFAValue::isRegisterPlusOffset || 98 RegisterNumber(thread, unwind_plan.GetRegisterKind(), 99 first_row->GetCFAValue().GetRegisterNumber()) != 100 sp_regnum || 101 first_row->GetCFAValue().GetOffset() != wordsize) { 102 return false; 103 } 104 UnwindPlan::Row::RegisterLocation first_row_pc_loc; 105 if (first_row->GetRegisterInfo( 106 pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()), 107 first_row_pc_loc) == false || 108 first_row_pc_loc.IsAtCFAPlusOffset() == false || 109 first_row_pc_loc.GetOffset() != -wordsize) { 110 return false; 111 } 112 113 // It looks like the prologue is described. 114 // Is the epilogue described? If it is, no need to do any augmentation. 115 116 if (first_row != last_row && 117 first_row->GetOffset() != last_row->GetOffset()) { 118 // The first & last row have the same CFA register 119 // and the same CFA offset value 120 // and the CFA register is esp/rsp (the stack pointer). 121 122 // We're checking that both of them have an unwind rule like "CFA=esp+4" or 123 // CFA+rsp+8". 124 125 if (first_row->GetCFAValue().GetValueType() == 126 last_row->GetCFAValue().GetValueType() && 127 first_row->GetCFAValue().GetRegisterNumber() == 128 last_row->GetCFAValue().GetRegisterNumber() && 129 first_row->GetCFAValue().GetOffset() == 130 last_row->GetCFAValue().GetOffset()) { 131 // Get the register locations for eip/rip from the first & last rows. 132 // Are they both CFA plus an offset? Is it the same offset? 133 134 UnwindPlan::Row::RegisterLocation last_row_pc_loc; 135 if (last_row->GetRegisterInfo( 136 pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()), 137 last_row_pc_loc)) { 138 if (last_row_pc_loc.IsAtCFAPlusOffset() && 139 first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset()) { 140 141 // One last sanity check: Is the unwind rule for getting the caller 142 // pc value 143 // "deref the CFA-4" or "deref the CFA-8"? 144 145 // If so, we have an UnwindPlan that already describes the epilogue 146 // and we don't need 147 // to modify it at all. 148 149 if (first_row_pc_loc.GetOffset() == -wordsize) { 150 do_augment_unwindplan = false; 151 } 152 } 153 } 154 } 155 } 156 157 if (do_augment_unwindplan) { 158 if (!func.GetBaseAddress().IsValid() || func.GetByteSize() == 0) 159 return false; 160 if (m_assembly_inspection_engine == nullptr) 161 return false; 162 const bool prefer_file_cache = true; 163 std::vector<uint8_t> function_text(func.GetByteSize()); 164 Error error; 165 if (process_sp->GetTarget().ReadMemory( 166 func.GetBaseAddress(), prefer_file_cache, function_text.data(), 167 func.GetByteSize(), error) == func.GetByteSize()) { 168 RegisterContextSP reg_ctx(thread.GetRegisterContext()); 169 m_assembly_inspection_engine->Initialize(reg_ctx); 170 return m_assembly_inspection_engine->AugmentUnwindPlanFromCallSite( 171 function_text.data(), func.GetByteSize(), func, unwind_plan, reg_ctx); 172 } 173 } 174 175 return false; 176 } 177 178 bool UnwindAssembly_x86::GetFastUnwindPlan(AddressRange &func, Thread &thread, 179 UnwindPlan &unwind_plan) { 180 // if prologue is 181 // 55 pushl %ebp 182 // 89 e5 movl %esp, %ebp 183 // or 184 // 55 pushq %rbp 185 // 48 89 e5 movq %rsp, %rbp 186 187 // We should pull in the ABI architecture default unwind plan and return that 188 189 llvm::SmallVector<uint8_t, 4> opcode_data; 190 191 ProcessSP process_sp = thread.GetProcess(); 192 if (process_sp) { 193 Target &target(process_sp->GetTarget()); 194 const bool prefer_file_cache = true; 195 Error error; 196 if (target.ReadMemory(func.GetBaseAddress(), prefer_file_cache, 197 opcode_data.data(), 4, error) == 4) { 198 uint8_t i386_push_mov[] = {0x55, 0x89, 0xe5}; 199 uint8_t x86_64_push_mov[] = {0x55, 0x48, 0x89, 0xe5}; 200 201 if (memcmp(opcode_data.data(), i386_push_mov, sizeof(i386_push_mov)) == 202 0 || 203 memcmp(opcode_data.data(), x86_64_push_mov, 204 sizeof(x86_64_push_mov)) == 0) { 205 ABISP abi_sp = process_sp->GetABI(); 206 if (abi_sp) { 207 return abi_sp->CreateDefaultUnwindPlan(unwind_plan); 208 } 209 } 210 } 211 } 212 return false; 213 } 214 215 bool UnwindAssembly_x86::FirstNonPrologueInsn( 216 AddressRange &func, const ExecutionContext &exe_ctx, 217 Address &first_non_prologue_insn) { 218 219 if (!func.GetBaseAddress().IsValid()) 220 return false; 221 222 Target *target = exe_ctx.GetTargetPtr(); 223 if (target == nullptr) 224 return false; 225 226 if (m_assembly_inspection_engine == nullptr) 227 return false; 228 229 const bool prefer_file_cache = true; 230 std::vector<uint8_t> function_text(func.GetByteSize()); 231 Error error; 232 if (target->ReadMemory(func.GetBaseAddress(), prefer_file_cache, 233 function_text.data(), func.GetByteSize(), 234 error) == func.GetByteSize()) { 235 size_t offset; 236 if (m_assembly_inspection_engine->FindFirstNonPrologueInstruction( 237 function_text.data(), func.GetByteSize(), offset)) { 238 first_non_prologue_insn = func.GetBaseAddress(); 239 first_non_prologue_insn.Slide(offset); 240 } 241 return true; 242 } 243 return false; 244 } 245 246 UnwindAssembly *UnwindAssembly_x86::CreateInstance(const ArchSpec &arch) { 247 const llvm::Triple::ArchType cpu = arch.GetMachine(); 248 if (cpu == llvm::Triple::x86 || cpu == llvm::Triple::x86_64) 249 return new UnwindAssembly_x86(arch); 250 return NULL; 251 } 252 253 //------------------------------------------------------------------ 254 // PluginInterface protocol in UnwindAssemblyParser_x86 255 //------------------------------------------------------------------ 256 257 ConstString UnwindAssembly_x86::GetPluginName() { 258 return GetPluginNameStatic(); 259 } 260 261 uint32_t UnwindAssembly_x86::GetPluginVersion() { return 1; } 262 263 void UnwindAssembly_x86::Initialize() { 264 PluginManager::RegisterPlugin(GetPluginNameStatic(), 265 GetPluginDescriptionStatic(), CreateInstance); 266 } 267 268 void UnwindAssembly_x86::Terminate() { 269 PluginManager::UnregisterPlugin(CreateInstance); 270 } 271 272 lldb_private::ConstString UnwindAssembly_x86::GetPluginNameStatic() { 273 static ConstString g_name("x86"); 274 return g_name; 275 } 276 277 const char *UnwindAssembly_x86::GetPluginDescriptionStatic() { 278 return "i386 and x86_64 assembly language profiler plugin."; 279 } 280