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