FuncUnwinders.cpp revision 309124
155714Skris//===-- FuncUnwinders.cpp ----------------------------------*- C++ -*-===// 255714Skris// 355714Skris// The LLVM Compiler Infrastructure 455714Skris// 555714Skris// This file is distributed under the University of Illinois Open Source 655714Skris// License. See LICENSE.TXT for details. 755714Skris// 8280304Sjkim//===----------------------------------------------------------------------===// 9280304Sjkim 1055714Skris#include "lldb/Core/AddressRange.h" 11280304Sjkim#include "lldb/Core/Address.h" 12280304Sjkim#include "lldb/Symbol/FuncUnwinders.h" 13280304Sjkim#include "lldb/Symbol/ArmUnwindInfo.h" 14280304Sjkim#include "lldb/Symbol/DWARFCallFrameInfo.h" 15280304Sjkim#include "lldb/Symbol/CompactUnwindInfo.h" 16280304Sjkim#include "lldb/Symbol/ObjectFile.h" 17280304Sjkim#include "lldb/Symbol/UnwindPlan.h" 18280304Sjkim#include "lldb/Symbol/UnwindTable.h" 19280304Sjkim#include "lldb/Target/ABI.h" 20280304Sjkim#include "lldb/Target/ExecutionContext.h" 21280304Sjkim#include "lldb/Target/Process.h" 22280304Sjkim#include "lldb/Target/Thread.h" 2355714Skris#include "lldb/Target/Target.h" 2455714Skris#include "lldb/Target/UnwindAssembly.h" 25280304Sjkim#include "lldb/Utility/RegisterNumber.h" 26280304Sjkim 27280304Sjkimusing namespace lldb; 2855714Skrisusing namespace lldb_private; 29280304Sjkim 30280304Sjkim//------------------------------------------------ 3155714Skris/// constructor 32280304Sjkim//------------------------------------------------ 33280304Sjkim 3455714SkrisFuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, AddressRange range) 3555714Skris : m_unwind_table(unwind_table), 36280304Sjkim m_range(range), 37280304Sjkim m_mutex(), 38280304Sjkim m_unwind_plan_assembly_sp(), 39280304Sjkim m_unwind_plan_eh_frame_sp(), 40280304Sjkim m_unwind_plan_eh_frame_augmented_sp(), 41280304Sjkim m_unwind_plan_compact_unwind(), 42280304Sjkim m_unwind_plan_arm_unwind_sp(), 43280304Sjkim m_unwind_plan_fast_sp(), 44280304Sjkim m_unwind_plan_arch_default_sp(), 45280304Sjkim m_unwind_plan_arch_default_at_func_entry_sp(), 46280304Sjkim m_tried_unwind_plan_assembly(false), 47280304Sjkim m_tried_unwind_plan_eh_frame(false), 48280304Sjkim m_tried_unwind_plan_eh_frame_augmented(false), 49280304Sjkim m_tried_unwind_plan_compact_unwind(false), 5055714Skris m_tried_unwind_plan_arm_unwind(false), 5155714Skris m_tried_unwind_fast(false), 52280304Sjkim m_tried_unwind_arch_default(false), 53280304Sjkim m_tried_unwind_arch_default_at_func_entry(false), 54280304Sjkim m_first_non_prologue_insn() 5555714Skris{ 56280304Sjkim} 57280304Sjkim 58280304Sjkim//------------------------------------------------ 59280304Sjkim/// destructor 60280304Sjkim//------------------------------------------------ 61280304Sjkim 62280304SjkimFuncUnwinders::~FuncUnwinders () 63280304Sjkim{ 64280304Sjkim} 65280304Sjkim 66280304SjkimUnwindPlanSP 67FuncUnwinders::GetUnwindPlanAtCallSite (Target &target, int current_offset) 68{ 69 std::lock_guard<std::recursive_mutex> guard(m_mutex); 70 71 UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, current_offset); 72 if (unwind_plan_sp) 73 return unwind_plan_sp; 74 75 unwind_plan_sp = GetCompactUnwindUnwindPlan (target, current_offset); 76 if (unwind_plan_sp) 77 return unwind_plan_sp; 78 79 unwind_plan_sp = GetArmUnwindUnwindPlan (target, current_offset); 80 if (unwind_plan_sp) 81 return unwind_plan_sp; 82 83 return nullptr; 84} 85 86UnwindPlanSP 87FuncUnwinders::GetCompactUnwindUnwindPlan (Target &target, int current_offset) 88{ 89 if (m_unwind_plan_compact_unwind.size() > 0) 90 return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact unwind plans for one func 91 if (m_tried_unwind_plan_compact_unwind) 92 return UnwindPlanSP(); 93 94 std::lock_guard<std::recursive_mutex> guard(m_mutex); 95 m_tried_unwind_plan_compact_unwind = true; 96 if (m_range.GetBaseAddress().IsValid()) 97 { 98 Address current_pc (m_range.GetBaseAddress ()); 99 if (current_offset != -1) 100 current_pc.SetOffset (current_pc.GetOffset() + current_offset); 101 CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo(); 102 if (compact_unwind) 103 { 104 UnwindPlanSP unwind_plan_sp (new UnwindPlan (lldb::eRegisterKindGeneric)); 105 if (compact_unwind->GetUnwindPlan (target, current_pc, *unwind_plan_sp)) 106 { 107 m_unwind_plan_compact_unwind.push_back (unwind_plan_sp); 108 return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact unwind plans for one func 109 } 110 } 111 } 112 return UnwindPlanSP(); 113} 114 115UnwindPlanSP 116FuncUnwinders::GetEHFrameUnwindPlan (Target &target, int current_offset) 117{ 118 if (m_unwind_plan_eh_frame_sp.get() || m_tried_unwind_plan_eh_frame) 119 return m_unwind_plan_eh_frame_sp; 120 121 std::lock_guard<std::recursive_mutex> guard(m_mutex); 122 m_tried_unwind_plan_eh_frame = true; 123 if (m_range.GetBaseAddress().IsValid()) 124 { 125 Address current_pc (m_range.GetBaseAddress ()); 126 if (current_offset != -1) 127 current_pc.SetOffset (current_pc.GetOffset() + current_offset); 128 DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo(); 129 if (eh_frame) 130 { 131 m_unwind_plan_eh_frame_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 132 if (!eh_frame->GetUnwindPlan (current_pc, *m_unwind_plan_eh_frame_sp)) 133 m_unwind_plan_eh_frame_sp.reset(); 134 } 135 } 136 return m_unwind_plan_eh_frame_sp; 137} 138 139UnwindPlanSP 140FuncUnwinders::GetArmUnwindUnwindPlan (Target &target, int current_offset) 141{ 142 if (m_unwind_plan_arm_unwind_sp.get() || m_tried_unwind_plan_arm_unwind) 143 return m_unwind_plan_arm_unwind_sp; 144 145 std::lock_guard<std::recursive_mutex> guard(m_mutex); 146 m_tried_unwind_plan_arm_unwind = true; 147 if (m_range.GetBaseAddress().IsValid()) 148 { 149 Address current_pc (m_range.GetBaseAddress ()); 150 if (current_offset != -1) 151 current_pc.SetOffset (current_pc.GetOffset() + current_offset); 152 ArmUnwindInfo *arm_unwind_info = m_unwind_table.GetArmUnwindInfo(); 153 if (arm_unwind_info) 154 { 155 m_unwind_plan_arm_unwind_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 156 if (!arm_unwind_info->GetUnwindPlan (target, current_pc, *m_unwind_plan_arm_unwind_sp)) 157 m_unwind_plan_arm_unwind_sp.reset(); 158 } 159 } 160 return m_unwind_plan_arm_unwind_sp; 161} 162 163UnwindPlanSP 164FuncUnwinders::GetEHFrameAugmentedUnwindPlan (Target &target, Thread &thread, int current_offset) 165{ 166 if (m_unwind_plan_eh_frame_augmented_sp.get() || m_tried_unwind_plan_eh_frame_augmented) 167 return m_unwind_plan_eh_frame_augmented_sp; 168 169 // Only supported on x86 architectures where we get eh_frame from the compiler that describes 170 // the prologue instructions perfectly, and sometimes the epilogue instructions too. 171 if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 172 && target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 173 && target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) 174 { 175 m_tried_unwind_plan_eh_frame_augmented = true; 176 return m_unwind_plan_eh_frame_augmented_sp; 177 } 178 179 std::lock_guard<std::recursive_mutex> guard(m_mutex); 180 m_tried_unwind_plan_eh_frame_augmented = true; 181 182 UnwindPlanSP eh_frame_plan = GetEHFrameUnwindPlan (target, current_offset); 183 if (!eh_frame_plan) 184 return m_unwind_plan_eh_frame_augmented_sp; 185 186 m_unwind_plan_eh_frame_augmented_sp.reset(new UnwindPlan(*eh_frame_plan)); 187 188 // Augment the eh_frame instructions with epilogue descriptions if necessary so the 189 // UnwindPlan can be used at any instruction in the function. 190 191 UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target)); 192 if (assembly_profiler_sp) 193 { 194 if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite (m_range, thread, *m_unwind_plan_eh_frame_augmented_sp)) 195 { 196 m_unwind_plan_eh_frame_augmented_sp.reset(); 197 } 198 } 199 else 200 { 201 m_unwind_plan_eh_frame_augmented_sp.reset(); 202 } 203 return m_unwind_plan_eh_frame_augmented_sp; 204} 205 206 207UnwindPlanSP 208FuncUnwinders::GetAssemblyUnwindPlan (Target &target, Thread &thread, int current_offset) 209{ 210 if (m_unwind_plan_assembly_sp.get() 211 || m_tried_unwind_plan_assembly 212 || m_unwind_table.GetAllowAssemblyEmulationUnwindPlans () == false) 213 { 214 return m_unwind_plan_assembly_sp; 215 } 216 217 std::lock_guard<std::recursive_mutex> guard(m_mutex); 218 m_tried_unwind_plan_assembly = true; 219 220 UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target)); 221 if (assembly_profiler_sp) 222 { 223 m_unwind_plan_assembly_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 224 if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_plan_assembly_sp)) 225 { 226 m_unwind_plan_assembly_sp.reset(); 227 } 228 } 229 return m_unwind_plan_assembly_sp; 230} 231 232// This method compares the pc unwind rule in the first row of two UnwindPlans. 233// If they have the same way of getting the pc value (e.g. "CFA - 8" + "CFA is sp"), 234// then it will return LazyBoolTrue. 235LazyBool 236FuncUnwinders::CompareUnwindPlansForIdenticalInitialPCLocation (Thread& thread, const UnwindPlanSP &a, const UnwindPlanSP &b) 237{ 238 LazyBool plans_are_identical = eLazyBoolCalculate; 239 240 RegisterNumber pc_reg (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); 241 uint32_t pc_reg_lldb_regnum = pc_reg.GetAsKind (eRegisterKindLLDB); 242 243 if (a.get() && b.get()) 244 { 245 UnwindPlan::RowSP a_first_row = a->GetRowAtIndex (0); 246 UnwindPlan::RowSP b_first_row = b->GetRowAtIndex (0); 247 248 if (a_first_row.get() && b_first_row.get()) 249 { 250 UnwindPlan::Row::RegisterLocation a_pc_regloc; 251 UnwindPlan::Row::RegisterLocation b_pc_regloc; 252 253 a_first_row->GetRegisterInfo (pc_reg_lldb_regnum, a_pc_regloc); 254 b_first_row->GetRegisterInfo (pc_reg_lldb_regnum, b_pc_regloc); 255 256 plans_are_identical = eLazyBoolYes; 257 258 if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue()) 259 { 260 plans_are_identical = eLazyBoolNo; 261 } 262 if (a_pc_regloc != b_pc_regloc) 263 { 264 plans_are_identical = eLazyBoolNo; 265 } 266 } 267 } 268 return plans_are_identical; 269} 270 271UnwindPlanSP 272FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int current_offset) 273{ 274 UnwindPlanSP eh_frame_sp = GetEHFrameUnwindPlan (target, current_offset); 275 UnwindPlanSP arch_default_at_entry_sp = GetUnwindPlanArchitectureDefaultAtFunctionEntry (thread); 276 UnwindPlanSP arch_default_sp = GetUnwindPlanArchitectureDefault (thread); 277 UnwindPlanSP assembly_sp = GetAssemblyUnwindPlan (target, thread, current_offset); 278 279 // This point of this code is to detect when a function is using a non-standard ABI, and the eh_frame 280 // correctly describes that alternate ABI. This is addressing a specific situation on x86_64 linux 281 // systems where one function in a library pushes a value on the stack and jumps to another function. 282 // So using an assembly instruction based unwind will not work when you're in the second function - 283 // the stack has been modified in a non-ABI way. But we have eh_frame that correctly describes how to 284 // unwind from this location. So we're looking to see if the initial pc register save location from 285 // the eh_frame is different from the assembly unwind, the arch default unwind, and the arch default at 286 // initial function entry. 287 // 288 // We may have eh_frame that describes the entire function -- or we may have eh_frame that only describes 289 // the unwind after the prologue has executed -- so we need to check both the arch default (once the prologue 290 // has executed) and the arch default at initial function entry. And we may be running on a target where 291 // we have only some of the assembly/arch default unwind plans available. 292 293 if (CompareUnwindPlansForIdenticalInitialPCLocation (thread, eh_frame_sp, arch_default_at_entry_sp) == eLazyBoolNo 294 && CompareUnwindPlansForIdenticalInitialPCLocation (thread, eh_frame_sp, arch_default_sp) == eLazyBoolNo 295 && CompareUnwindPlansForIdenticalInitialPCLocation (thread, assembly_sp, arch_default_sp) == eLazyBoolNo) 296 { 297 return eh_frame_sp; 298 } 299 300 UnwindPlanSP eh_frame_augmented_sp = GetEHFrameAugmentedUnwindPlan (target, thread, current_offset); 301 if (eh_frame_augmented_sp) 302 { 303 return eh_frame_augmented_sp; 304 } 305 306 return assembly_sp; 307} 308 309UnwindPlanSP 310FuncUnwinders::GetUnwindPlanFastUnwind (Target& target, Thread& thread) 311{ 312 if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast) 313 return m_unwind_plan_fast_sp; 314 315 std::lock_guard<std::recursive_mutex> guard(m_mutex); 316 m_tried_unwind_fast = true; 317 318 UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target)); 319 if (assembly_profiler_sp) 320 { 321 m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 322 if (!assembly_profiler_sp->GetFastUnwindPlan (m_range, thread, *m_unwind_plan_fast_sp)) 323 { 324 m_unwind_plan_fast_sp.reset(); 325 } 326 } 327 return m_unwind_plan_fast_sp; 328} 329 330UnwindPlanSP 331FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread) 332{ 333 if (m_unwind_plan_arch_default_sp.get() || m_tried_unwind_arch_default) 334 return m_unwind_plan_arch_default_sp; 335 336 std::lock_guard<std::recursive_mutex> guard(m_mutex); 337 m_tried_unwind_arch_default = true; 338 339 Address current_pc; 340 ProcessSP process_sp (thread.CalculateProcess()); 341 if (process_sp) 342 { 343 ABI *abi = process_sp->GetABI().get(); 344 if (abi) 345 { 346 m_unwind_plan_arch_default_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 347 if (!abi->CreateDefaultUnwindPlan(*m_unwind_plan_arch_default_sp)) 348 { 349 m_unwind_plan_arch_default_sp.reset(); 350 } 351 } 352 } 353 354 return m_unwind_plan_arch_default_sp; 355} 356 357UnwindPlanSP 358FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry (Thread& thread) 359{ 360 if (m_unwind_plan_arch_default_at_func_entry_sp.get() || m_tried_unwind_arch_default_at_func_entry) 361 return m_unwind_plan_arch_default_at_func_entry_sp; 362 363 std::lock_guard<std::recursive_mutex> guard(m_mutex); 364 m_tried_unwind_arch_default_at_func_entry = true; 365 366 Address current_pc; 367 ProcessSP process_sp (thread.CalculateProcess()); 368 if (process_sp) 369 { 370 ABI *abi = process_sp->GetABI().get(); 371 if (abi) 372 { 373 m_unwind_plan_arch_default_at_func_entry_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 374 if (!abi->CreateFunctionEntryUnwindPlan(*m_unwind_plan_arch_default_at_func_entry_sp)) 375 { 376 m_unwind_plan_arch_default_at_func_entry_sp.reset(); 377 } 378 } 379 } 380 381 return m_unwind_plan_arch_default_at_func_entry_sp; 382} 383 384 385Address& 386FuncUnwinders::GetFirstNonPrologueInsn (Target& target) 387{ 388 if (m_first_non_prologue_insn.IsValid()) 389 return m_first_non_prologue_insn; 390 391 std::lock_guard<std::recursive_mutex> guard(m_mutex); 392 ExecutionContext exe_ctx (target.shared_from_this(), false); 393 UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target)); 394 if (assembly_profiler_sp) 395 assembly_profiler_sp->FirstNonPrologueInsn (m_range, exe_ctx, m_first_non_prologue_insn); 396 return m_first_non_prologue_insn; 397} 398 399const Address& 400FuncUnwinders::GetFunctionStartAddress () const 401{ 402 return m_range.GetBaseAddress(); 403} 404 405lldb::UnwindAssemblySP 406FuncUnwinders::GetUnwindAssemblyProfiler (Target& target) 407{ 408 UnwindAssemblySP assembly_profiler_sp; 409 ArchSpec arch; 410 if (m_unwind_table.GetArchitecture (arch)) 411 { 412 arch.MergeFrom (target.GetArchitecture ()); 413 assembly_profiler_sp = UnwindAssembly::FindPlugin (arch); 414 } 415 return assembly_profiler_sp; 416} 417 418Address 419FuncUnwinders::GetLSDAAddress (Target &target) 420{ 421 Address lsda_addr; 422 423 UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, -1); 424 if (unwind_plan_sp.get() == nullptr) 425 { 426 unwind_plan_sp = GetCompactUnwindUnwindPlan (target, -1); 427 } 428 if (unwind_plan_sp.get() && unwind_plan_sp->GetLSDAAddress().IsValid()) 429 { 430 lsda_addr = unwind_plan_sp->GetLSDAAddress(); 431 } 432 return lsda_addr; 433} 434 435 436Address 437FuncUnwinders::GetPersonalityRoutinePtrAddress (Target &target) 438{ 439 Address personality_addr; 440 441 UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, -1); 442 if (unwind_plan_sp.get() == nullptr) 443 { 444 unwind_plan_sp = GetCompactUnwindUnwindPlan (target, -1); 445 } 446 if (unwind_plan_sp.get() && unwind_plan_sp->GetPersonalityFunctionPtr().IsValid()) 447 { 448 personality_addr = unwind_plan_sp->GetPersonalityFunctionPtr(); 449 } 450 451 return personality_addr; 452} 453