FuncUnwinders.cpp revision 288943
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    UnwindPlanSP eh_frame_plan = GetEHFrameUnwindPlan (target, current_offset);
149    if (!eh_frame_plan)
150        return m_unwind_plan_eh_frame_augmented_sp;
151
152    m_unwind_plan_eh_frame_augmented_sp.reset(new UnwindPlan(*eh_frame_plan));
153
154    // Augment the eh_frame instructions with epilogue descriptions if necessary so the
155    // UnwindPlan can be used at any instruction in the function.
156
157    UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
158    if (assembly_profiler_sp)
159    {
160        if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite (m_range, thread, *m_unwind_plan_eh_frame_augmented_sp))
161        {
162            m_unwind_plan_eh_frame_augmented_sp.reset();
163        }
164    }
165    else
166    {
167        m_unwind_plan_eh_frame_augmented_sp.reset();
168    }
169    return m_unwind_plan_eh_frame_augmented_sp;
170}
171
172
173UnwindPlanSP
174FuncUnwinders::GetAssemblyUnwindPlan (Target &target, Thread &thread, int current_offset)
175{
176    if (m_unwind_plan_assembly_sp.get() || m_tried_unwind_plan_assembly)
177        return m_unwind_plan_assembly_sp;
178
179    Mutex::Locker lock (m_mutex);
180    m_tried_unwind_plan_assembly = true;
181
182    UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
183    if (assembly_profiler_sp)
184    {
185        m_unwind_plan_assembly_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
186        if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_plan_assembly_sp))
187        {
188            m_unwind_plan_assembly_sp.reset();
189        }
190    }
191    return m_unwind_plan_assembly_sp;
192}
193
194
195UnwindPlanSP
196FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int current_offset)
197{
198    UnwindPlanSP non_call_site_unwindplan_sp = GetEHFrameAugmentedUnwindPlan (target, thread, current_offset);
199    if (non_call_site_unwindplan_sp.get() == nullptr)
200    {
201        non_call_site_unwindplan_sp = GetAssemblyUnwindPlan (target, thread, current_offset);
202    }
203    return non_call_site_unwindplan_sp;
204}
205
206UnwindPlanSP
207FuncUnwinders::GetUnwindPlanFastUnwind (Target& target, Thread& thread)
208{
209    if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast)
210        return m_unwind_plan_fast_sp;
211
212    Mutex::Locker locker (m_mutex);
213    m_tried_unwind_fast = true;
214
215    UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
216    if (assembly_profiler_sp)
217    {
218        m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
219        if (!assembly_profiler_sp->GetFastUnwindPlan (m_range, thread, *m_unwind_plan_fast_sp))
220        {
221            m_unwind_plan_fast_sp.reset();
222        }
223    }
224    return m_unwind_plan_fast_sp;
225}
226
227UnwindPlanSP
228FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread)
229{
230    if (m_unwind_plan_arch_default_sp.get() || m_tried_unwind_arch_default)
231        return m_unwind_plan_arch_default_sp;
232
233    Mutex::Locker locker (m_mutex);
234    m_tried_unwind_arch_default = true;
235
236    Address current_pc;
237    ProcessSP process_sp (thread.CalculateProcess());
238    if (process_sp)
239    {
240        ABI *abi = process_sp->GetABI().get();
241        if (abi)
242        {
243            m_unwind_plan_arch_default_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
244            if (!abi->CreateDefaultUnwindPlan(*m_unwind_plan_arch_default_sp))
245            {
246                m_unwind_plan_arch_default_sp.reset();
247            }
248        }
249    }
250
251    return m_unwind_plan_arch_default_sp;
252}
253
254UnwindPlanSP
255FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry (Thread& thread)
256{
257    if (m_unwind_plan_arch_default_at_func_entry_sp.get() || m_tried_unwind_arch_default_at_func_entry)
258        return m_unwind_plan_arch_default_at_func_entry_sp;
259
260    Mutex::Locker locker (m_mutex);
261    m_tried_unwind_arch_default_at_func_entry = true;
262
263    Address current_pc;
264    ProcessSP process_sp (thread.CalculateProcess());
265    if (process_sp)
266    {
267        ABI *abi = process_sp->GetABI().get();
268        if (abi)
269        {
270            m_unwind_plan_arch_default_at_func_entry_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
271            if (!abi->CreateFunctionEntryUnwindPlan(*m_unwind_plan_arch_default_at_func_entry_sp))
272            {
273                m_unwind_plan_arch_default_at_func_entry_sp.reset();
274            }
275        }
276    }
277
278    return m_unwind_plan_arch_default_at_func_entry_sp;
279}
280
281
282Address&
283FuncUnwinders::GetFirstNonPrologueInsn (Target& target)
284{
285    if (m_first_non_prologue_insn.IsValid())
286        return m_first_non_prologue_insn;
287
288    Mutex::Locker locker (m_mutex);
289    ExecutionContext exe_ctx (target.shared_from_this(), false);
290    UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
291    if (assembly_profiler_sp)
292        assembly_profiler_sp->FirstNonPrologueInsn (m_range, exe_ctx, m_first_non_prologue_insn);
293    return m_first_non_prologue_insn;
294}
295
296const Address&
297FuncUnwinders::GetFunctionStartAddress () const
298{
299    return m_range.GetBaseAddress();
300}
301
302lldb::UnwindAssemblySP
303FuncUnwinders::GetUnwindAssemblyProfiler (Target& target)
304{
305    UnwindAssemblySP assembly_profiler_sp;
306    ArchSpec arch;
307    if (m_unwind_table.GetArchitecture (arch))
308    {
309        arch.MergeFrom (target.GetArchitecture ());
310        assembly_profiler_sp = UnwindAssembly::FindPlugin (arch);
311    }
312    return assembly_profiler_sp;
313}
314
315Address
316FuncUnwinders::GetLSDAAddress (Target &target)
317{
318    Address lsda_addr;
319
320    UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, -1);
321    if (unwind_plan_sp.get() == nullptr)
322    {
323        unwind_plan_sp = GetCompactUnwindUnwindPlan (target, -1);
324    }
325    if (unwind_plan_sp.get() && unwind_plan_sp->GetLSDAAddress().IsValid())
326    {
327        lsda_addr = unwind_plan_sp->GetLSDAAddress();
328    }
329    return lsda_addr;
330}
331
332
333Address
334FuncUnwinders::GetPersonalityRoutinePtrAddress (Target &target)
335{
336    Address personality_addr;
337
338    UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, -1);
339    if (unwind_plan_sp.get() == nullptr)
340    {
341        unwind_plan_sp = GetCompactUnwindUnwindPlan (target, -1);
342    }
343    if (unwind_plan_sp.get() && unwind_plan_sp->GetPersonalityFunctionPtr().IsValid())
344    {
345        personality_addr = unwind_plan_sp->GetPersonalityFunctionPtr();
346    }
347
348    return personality_addr;
349}
350