FuncUnwinders.cpp revision 280031
1//===-- FuncUnwinders.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 "lldb/Core/AddressRange.h" 11#include "lldb/Core/Address.h" 12#include "lldb/Symbol/FuncUnwinders.h" 13#include "lldb/Symbol/DWARFCallFrameInfo.h" 14#include "lldb/Symbol/CompactUnwindInfo.h" 15#include "lldb/Symbol/ObjectFile.h" 16#include "lldb/Symbol/UnwindPlan.h" 17#include "lldb/Symbol/UnwindTable.h" 18#include "lldb/Target/ABI.h" 19#include "lldb/Target/ExecutionContext.h" 20#include "lldb/Target/Process.h" 21#include "lldb/Target/Thread.h" 22#include "lldb/Target/Target.h" 23#include "lldb/Target/UnwindAssembly.h" 24 25using namespace lldb; 26using namespace lldb_private; 27 28//------------------------------------------------ 29/// constructor 30//------------------------------------------------ 31 32FuncUnwinders::FuncUnwinders (UnwindTable& unwind_table, AddressRange range) : 33 m_unwind_table (unwind_table), 34 m_range (range), 35 m_mutex (Mutex::eMutexTypeRecursive), 36 m_unwind_plan_assembly_sp (), 37 m_unwind_plan_eh_frame_sp (), 38 m_unwind_plan_eh_frame_augmented_sp (), 39 m_unwind_plan_compact_unwind (), 40 m_unwind_plan_fast_sp (), 41 m_unwind_plan_arch_default_sp (), 42 m_unwind_plan_arch_default_at_func_entry_sp (), 43 m_tried_unwind_plan_assembly (false), 44 m_tried_unwind_plan_eh_frame (false), 45 m_tried_unwind_plan_eh_frame_augmented (false), 46 m_tried_unwind_plan_compact_unwind (false), 47 m_tried_unwind_fast (false), 48 m_tried_unwind_arch_default (false), 49 m_tried_unwind_arch_default_at_func_entry (false), 50 m_first_non_prologue_insn () 51{ 52} 53 54//------------------------------------------------ 55/// destructor 56//------------------------------------------------ 57 58FuncUnwinders::~FuncUnwinders () 59{ 60} 61 62UnwindPlanSP 63FuncUnwinders::GetUnwindPlanAtCallSite (Target &target, int current_offset) 64{ 65 Mutex::Locker locker (m_mutex); 66 67 UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, current_offset); 68 if (unwind_plan_sp.get() == nullptr) 69 { 70 unwind_plan_sp = GetCompactUnwindUnwindPlan (target, current_offset); 71 } 72 73 return unwind_plan_sp; 74} 75 76UnwindPlanSP 77FuncUnwinders::GetCompactUnwindUnwindPlan (Target &target, int current_offset) 78{ 79 if (m_unwind_plan_compact_unwind.size() > 0) 80 return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact unwind plans for one func 81 if (m_tried_unwind_plan_compact_unwind) 82 return UnwindPlanSP(); 83 84 Mutex::Locker lock (m_mutex); 85 m_tried_unwind_plan_compact_unwind = true; 86 if (m_range.GetBaseAddress().IsValid()) 87 { 88 Address current_pc (m_range.GetBaseAddress ()); 89 if (current_offset != -1) 90 current_pc.SetOffset (current_pc.GetOffset() + current_offset); 91 CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo(); 92 if (compact_unwind) 93 { 94 UnwindPlanSP unwind_plan_sp (new UnwindPlan (lldb::eRegisterKindGeneric)); 95 if (compact_unwind->GetUnwindPlan (target, current_pc, *unwind_plan_sp)) 96 { 97 m_unwind_plan_compact_unwind.push_back (unwind_plan_sp); 98 return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact unwind plans for one func 99 } 100 } 101 } 102 return UnwindPlanSP(); 103} 104 105UnwindPlanSP 106FuncUnwinders::GetEHFrameUnwindPlan (Target &target, int current_offset) 107{ 108 if (m_unwind_plan_eh_frame_sp.get() || m_tried_unwind_plan_eh_frame) 109 return m_unwind_plan_eh_frame_sp; 110 111 Mutex::Locker lock (m_mutex); 112 m_tried_unwind_plan_eh_frame = true; 113 if (m_range.GetBaseAddress().IsValid()) 114 { 115 Address current_pc (m_range.GetBaseAddress ()); 116 if (current_offset != -1) 117 current_pc.SetOffset (current_pc.GetOffset() + current_offset); 118 DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo(); 119 if (eh_frame) 120 { 121 m_unwind_plan_eh_frame_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 122 if (!eh_frame->GetUnwindPlan (current_pc, *m_unwind_plan_eh_frame_sp)) 123 m_unwind_plan_eh_frame_sp.reset(); 124 } 125 } 126 return m_unwind_plan_eh_frame_sp; 127} 128 129UnwindPlanSP 130FuncUnwinders::GetEHFrameAugmentedUnwindPlan (Target &target, Thread &thread, int current_offset) 131{ 132 if (m_unwind_plan_eh_frame_augmented_sp.get() || m_tried_unwind_plan_eh_frame_augmented) 133 return m_unwind_plan_eh_frame_augmented_sp; 134 135 // Only supported on x86 architectures where we get eh_frame from the compiler that describes 136 // the prologue instructions perfectly, and sometimes the epilogue instructions too. 137 if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 138 && target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 139 && target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) 140 { 141 m_tried_unwind_plan_eh_frame_augmented = true; 142 return m_unwind_plan_eh_frame_augmented_sp; 143 } 144 145 Mutex::Locker lock (m_mutex); 146 m_tried_unwind_plan_eh_frame_augmented = true; 147 148 if (m_range.GetBaseAddress().IsValid()) 149 { 150 Address current_pc (m_range.GetBaseAddress ()); 151 if (current_offset != -1) 152 current_pc.SetOffset (current_pc.GetOffset() + current_offset); 153 DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo(); 154 if (eh_frame) 155 { 156 m_unwind_plan_eh_frame_augmented_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 157 if (!eh_frame->GetUnwindPlan (current_pc, *m_unwind_plan_eh_frame_augmented_sp)) 158 { 159 m_unwind_plan_eh_frame_augmented_sp.reset(); 160 } 161 else 162 { 163 // Augment the eh_frame instructions with epilogue descriptions if necessary so the 164 // UnwindPlan can be used at any instruction in the function. 165 166 UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler()); 167 if (assembly_profiler_sp) 168 { 169 if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite (m_range, thread, *m_unwind_plan_eh_frame_augmented_sp)) 170 { 171 m_unwind_plan_eh_frame_augmented_sp.reset(); 172 } 173 } 174 else 175 { 176 m_unwind_plan_eh_frame_augmented_sp.reset(); 177 } 178 } 179 } 180 } 181 return m_unwind_plan_eh_frame_augmented_sp; 182} 183 184 185UnwindPlanSP 186FuncUnwinders::GetAssemblyUnwindPlan (Target &target, Thread &thread, int current_offset) 187{ 188 if (m_unwind_plan_assembly_sp.get() || m_tried_unwind_plan_assembly) 189 return m_unwind_plan_assembly_sp; 190 191 Mutex::Locker lock (m_mutex); 192 m_tried_unwind_plan_assembly = true; 193 194 UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler()); 195 if (assembly_profiler_sp) 196 { 197 m_unwind_plan_assembly_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 198 if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_plan_assembly_sp)) 199 { 200 m_unwind_plan_assembly_sp.reset(); 201 } 202 } 203 return m_unwind_plan_assembly_sp; 204} 205 206 207UnwindPlanSP 208FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int current_offset) 209{ 210 UnwindPlanSP non_call_site_unwindplan_sp = GetEHFrameAugmentedUnwindPlan (target, thread, current_offset); 211 if (non_call_site_unwindplan_sp.get() == nullptr) 212 { 213 non_call_site_unwindplan_sp = GetAssemblyUnwindPlan (target, thread, current_offset); 214 } 215 return non_call_site_unwindplan_sp; 216} 217 218UnwindPlanSP 219FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread) 220{ 221 if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast) 222 return m_unwind_plan_fast_sp; 223 224 Mutex::Locker locker (m_mutex); 225 m_tried_unwind_fast = true; 226 227 UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler()); 228 if (assembly_profiler_sp) 229 { 230 m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 231 if (!assembly_profiler_sp->GetFastUnwindPlan (m_range, thread, *m_unwind_plan_fast_sp)) 232 { 233 m_unwind_plan_fast_sp.reset(); 234 } 235 } 236 return m_unwind_plan_fast_sp; 237} 238 239UnwindPlanSP 240FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread) 241{ 242 if (m_unwind_plan_arch_default_sp.get() || m_tried_unwind_arch_default) 243 return m_unwind_plan_arch_default_sp; 244 245 Mutex::Locker locker (m_mutex); 246 m_tried_unwind_arch_default = true; 247 248 Address current_pc; 249 ProcessSP process_sp (thread.CalculateProcess()); 250 if (process_sp) 251 { 252 ABI *abi = process_sp->GetABI().get(); 253 if (abi) 254 { 255 m_unwind_plan_arch_default_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 256 if (!abi->CreateDefaultUnwindPlan(*m_unwind_plan_arch_default_sp)) 257 { 258 m_unwind_plan_arch_default_sp.reset(); 259 } 260 } 261 } 262 263 return m_unwind_plan_arch_default_sp; 264} 265 266UnwindPlanSP 267FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry (Thread& thread) 268{ 269 if (m_unwind_plan_arch_default_at_func_entry_sp.get() || m_tried_unwind_arch_default_at_func_entry) 270 return m_unwind_plan_arch_default_at_func_entry_sp; 271 272 Mutex::Locker locker (m_mutex); 273 m_tried_unwind_arch_default_at_func_entry = true; 274 275 Address current_pc; 276 ProcessSP process_sp (thread.CalculateProcess()); 277 if (process_sp) 278 { 279 ABI *abi = process_sp->GetABI().get(); 280 if (abi) 281 { 282 m_unwind_plan_arch_default_at_func_entry_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); 283 if (!abi->CreateFunctionEntryUnwindPlan(*m_unwind_plan_arch_default_at_func_entry_sp)) 284 { 285 m_unwind_plan_arch_default_at_func_entry_sp.reset(); 286 } 287 } 288 } 289 290 return m_unwind_plan_arch_default_at_func_entry_sp; 291} 292 293 294Address& 295FuncUnwinders::GetFirstNonPrologueInsn (Target& target) 296{ 297 if (m_first_non_prologue_insn.IsValid()) 298 return m_first_non_prologue_insn; 299 300 Mutex::Locker locker (m_mutex); 301 ExecutionContext exe_ctx (target.shared_from_this(), false); 302 UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler()); 303 if (assembly_profiler_sp) 304 assembly_profiler_sp->FirstNonPrologueInsn (m_range, exe_ctx, m_first_non_prologue_insn); 305 return m_first_non_prologue_insn; 306} 307 308const Address& 309FuncUnwinders::GetFunctionStartAddress () const 310{ 311 return m_range.GetBaseAddress(); 312} 313 314lldb::UnwindAssemblySP 315FuncUnwinders::GetUnwindAssemblyProfiler () 316{ 317 UnwindAssemblySP assembly_profiler_sp; 318 ArchSpec arch; 319 if (m_unwind_table.GetArchitecture (arch)) 320 { 321 assembly_profiler_sp = UnwindAssembly::FindPlugin (arch); 322 } 323 return assembly_profiler_sp; 324} 325 326Address 327FuncUnwinders::GetLSDAAddress (Target &target) 328{ 329 Address lsda_addr; 330 331 UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, -1); 332 if (unwind_plan_sp.get() == nullptr) 333 { 334 unwind_plan_sp = GetCompactUnwindUnwindPlan (target, -1); 335 } 336 if (unwind_plan_sp.get() && unwind_plan_sp->GetLSDAAddress().IsValid()) 337 { 338 lsda_addr = unwind_plan_sp->GetLSDAAddress(); 339 } 340 return lsda_addr; 341} 342 343 344Address 345FuncUnwinders::GetPersonalityRoutinePtrAddress (Target &target) 346{ 347 Address personality_addr; 348 349 UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, -1); 350 if (unwind_plan_sp.get() == nullptr) 351 { 352 unwind_plan_sp = GetCompactUnwindUnwindPlan (target, -1); 353 } 354 if (unwind_plan_sp.get() && unwind_plan_sp->GetPersonalityFunctionPtr().IsValid()) 355 { 356 personality_addr = unwind_plan_sp->GetPersonalityFunctionPtr(); 357 } 358 359 return personality_addr; 360} 361