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