CompactUnwindInfo.cpp revision 309124
1278332Semaste//===-- CompactUnwindInfo.cpp -----------------------------------*- C++ -*-===//
2278332Semaste//
3278332Semaste//                     The LLVM Compiler Infrastructure
4278332Semaste//
5278332Semaste// This file is distributed under the University of Illinois Open Source
6278332Semaste// License. See LICENSE.TXT for details.
7278332Semaste//
8278332Semaste//===----------------------------------------------------------------------===//
9278332Semaste
10278332Semaste
11278332Semaste// C Includes
12278332Semaste// C++ Includes
13278332Semaste#include <algorithm>
14278332Semaste
15278332Semaste#include "lldb/Core/ArchSpec.h"
16288943Sdim#include "lldb/Core/DataBufferHeap.h"
17278332Semaste#include "lldb/Core/Log.h"
18278332Semaste#include "lldb/Core/Module.h"
19278332Semaste#include "lldb/Core/Section.h"
20278332Semaste#include "lldb/Core/Section.h"
21278332Semaste#include "lldb/Core/StreamString.h"
22278332Semaste#include "lldb/Symbol/CompactUnwindInfo.h"
23278332Semaste#include "lldb/Symbol/ObjectFile.h"
24278332Semaste#include "lldb/Symbol/UnwindPlan.h"
25278332Semaste#include "lldb/Target/Process.h"
26278332Semaste#include "lldb/Target/Target.h"
27278332Semaste
28278332Semaste#include "llvm/Support/MathExtras.h"
29278332Semaste
30278332Semasteusing namespace lldb;
31278332Semasteusing namespace lldb_private;
32278332Semaste
33278332Semaste
34278332Semastenamespace lldb_private {
35278332Semaste
36278332Semaste    // Constants from <mach-o/compact_unwind_encoding.h>
37278332Semaste
38288943Sdim    FLAGS_ANONYMOUS_ENUM()
39288943Sdim    {
40278332Semaste        UNWIND_IS_NOT_FUNCTION_START           = 0x80000000,
41278332Semaste        UNWIND_HAS_LSDA                        = 0x40000000,
42278332Semaste        UNWIND_PERSONALITY_MASK                = 0x30000000,
43278332Semaste    };
44278332Semaste
45288943Sdim    FLAGS_ANONYMOUS_ENUM()
46288943Sdim    {
47278332Semaste        UNWIND_X86_MODE_MASK                         = 0x0F000000,
48278332Semaste        UNWIND_X86_MODE_EBP_FRAME                    = 0x01000000,
49278332Semaste        UNWIND_X86_MODE_STACK_IMMD                   = 0x02000000,
50278332Semaste        UNWIND_X86_MODE_STACK_IND                    = 0x03000000,
51278332Semaste        UNWIND_X86_MODE_DWARF                        = 0x04000000,
52278332Semaste
53278332Semaste        UNWIND_X86_EBP_FRAME_REGISTERS               = 0x00007FFF,
54278332Semaste        UNWIND_X86_EBP_FRAME_OFFSET                  = 0x00FF0000,
55278332Semaste
56278332Semaste        UNWIND_X86_FRAMELESS_STACK_SIZE              = 0x00FF0000,
57278332Semaste        UNWIND_X86_FRAMELESS_STACK_ADJUST            = 0x0000E000,
58278332Semaste        UNWIND_X86_FRAMELESS_STACK_REG_COUNT         = 0x00001C00,
59278332Semaste        UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION   = 0x000003FF,
60278332Semaste
61278332Semaste        UNWIND_X86_DWARF_SECTION_OFFSET              = 0x00FFFFFF,
62278332Semaste    };
63278332Semaste
64288943Sdim    enum
65288943Sdim    {
66278332Semaste        UNWIND_X86_REG_NONE     = 0,
67278332Semaste        UNWIND_X86_REG_EBX      = 1,
68278332Semaste        UNWIND_X86_REG_ECX      = 2,
69278332Semaste        UNWIND_X86_REG_EDX      = 3,
70278332Semaste        UNWIND_X86_REG_EDI      = 4,
71278332Semaste        UNWIND_X86_REG_ESI      = 5,
72278332Semaste        UNWIND_X86_REG_EBP      = 6,
73278332Semaste    };
74288943Sdim
75288943Sdim    FLAGS_ANONYMOUS_ENUM()
76288943Sdim    {
77278332Semaste        UNWIND_X86_64_MODE_MASK                         = 0x0F000000,
78278332Semaste        UNWIND_X86_64_MODE_RBP_FRAME                    = 0x01000000,
79278332Semaste        UNWIND_X86_64_MODE_STACK_IMMD                   = 0x02000000,
80278332Semaste        UNWIND_X86_64_MODE_STACK_IND                    = 0x03000000,
81278332Semaste        UNWIND_X86_64_MODE_DWARF                        = 0x04000000,
82278332Semaste
83278332Semaste        UNWIND_X86_64_RBP_FRAME_REGISTERS               = 0x00007FFF,
84278332Semaste        UNWIND_X86_64_RBP_FRAME_OFFSET                  = 0x00FF0000,
85278332Semaste
86278332Semaste        UNWIND_X86_64_FRAMELESS_STACK_SIZE              = 0x00FF0000,
87278332Semaste        UNWIND_X86_64_FRAMELESS_STACK_ADJUST            = 0x0000E000,
88278332Semaste        UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT         = 0x00001C00,
89278332Semaste        UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION   = 0x000003FF,
90278332Semaste
91278332Semaste        UNWIND_X86_64_DWARF_SECTION_OFFSET              = 0x00FFFFFF,
92278332Semaste    };
93278332Semaste
94288943Sdim    enum
95288943Sdim    {
96278332Semaste        UNWIND_X86_64_REG_NONE       = 0,
97278332Semaste        UNWIND_X86_64_REG_RBX        = 1,
98278332Semaste        UNWIND_X86_64_REG_R12        = 2,
99278332Semaste        UNWIND_X86_64_REG_R13        = 3,
100278332Semaste        UNWIND_X86_64_REG_R14        = 4,
101278332Semaste        UNWIND_X86_64_REG_R15        = 5,
102278332Semaste        UNWIND_X86_64_REG_RBP        = 6,
103278332Semaste    };
104309124Sdim
105309124Sdim    FLAGS_ANONYMOUS_ENUM()
106309124Sdim    {
107309124Sdim        UNWIND_ARM64_MODE_MASK                     = 0x0F000000,
108309124Sdim        UNWIND_ARM64_MODE_FRAMELESS                = 0x02000000,
109309124Sdim        UNWIND_ARM64_MODE_DWARF                    = 0x03000000,
110309124Sdim        UNWIND_ARM64_MODE_FRAME                    = 0x04000000,
111309124Sdim
112309124Sdim        UNWIND_ARM64_FRAME_X19_X20_PAIR            = 0x00000001,
113309124Sdim        UNWIND_ARM64_FRAME_X21_X22_PAIR            = 0x00000002,
114309124Sdim        UNWIND_ARM64_FRAME_X23_X24_PAIR            = 0x00000004,
115309124Sdim        UNWIND_ARM64_FRAME_X25_X26_PAIR            = 0x00000008,
116309124Sdim        UNWIND_ARM64_FRAME_X27_X28_PAIR            = 0x00000010,
117309124Sdim        UNWIND_ARM64_FRAME_D8_D9_PAIR              = 0x00000100,
118309124Sdim        UNWIND_ARM64_FRAME_D10_D11_PAIR            = 0x00000200,
119309124Sdim        UNWIND_ARM64_FRAME_D12_D13_PAIR            = 0x00000400,
120309124Sdim        UNWIND_ARM64_FRAME_D14_D15_PAIR            = 0x00000800,
121309124Sdim
122309124Sdim        UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK     = 0x00FFF000,
123309124Sdim        UNWIND_ARM64_DWARF_SECTION_OFFSET          = 0x00FFFFFF,
124309124Sdim    };
125309124Sdim
126309124Sdim    FLAGS_ANONYMOUS_ENUM()
127309124Sdim    {
128309124Sdim        UNWIND_ARM_MODE_MASK                         = 0x0F000000,
129309124Sdim        UNWIND_ARM_MODE_FRAME                        = 0x01000000,
130309124Sdim        UNWIND_ARM_MODE_FRAME_D                      = 0x02000000,
131309124Sdim        UNWIND_ARM_MODE_DWARF                        = 0x04000000,
132309124Sdim
133309124Sdim        UNWIND_ARM_FRAME_STACK_ADJUST_MASK           = 0x00C00000,
134309124Sdim
135309124Sdim        UNWIND_ARM_FRAME_FIRST_PUSH_R4               = 0x00000001,
136309124Sdim        UNWIND_ARM_FRAME_FIRST_PUSH_R5               = 0x00000002,
137309124Sdim        UNWIND_ARM_FRAME_FIRST_PUSH_R6               = 0x00000004,
138309124Sdim
139309124Sdim        UNWIND_ARM_FRAME_SECOND_PUSH_R8              = 0x00000008,
140309124Sdim        UNWIND_ARM_FRAME_SECOND_PUSH_R9              = 0x00000010,
141309124Sdim        UNWIND_ARM_FRAME_SECOND_PUSH_R10             = 0x00000020,
142309124Sdim        UNWIND_ARM_FRAME_SECOND_PUSH_R11             = 0x00000040,
143309124Sdim        UNWIND_ARM_FRAME_SECOND_PUSH_R12             = 0x00000080,
144309124Sdim
145309124Sdim        UNWIND_ARM_FRAME_D_REG_COUNT_MASK            = 0x00000700,
146309124Sdim
147309124Sdim        UNWIND_ARM_DWARF_SECTION_OFFSET              = 0x00FFFFFF,
148309124Sdim    };
149309124Sdim
150288943Sdim}
151278332Semaste
152278332Semaste
153278332Semaste#ifndef UNWIND_SECOND_LEVEL_REGULAR
154278332Semaste#define UNWIND_SECOND_LEVEL_REGULAR 2
155278332Semaste#endif
156278332Semaste
157278332Semaste#ifndef UNWIND_SECOND_LEVEL_COMPRESSED
158278332Semaste#define UNWIND_SECOND_LEVEL_COMPRESSED 3
159278332Semaste#endif
160278332Semaste
161278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
162278332Semaste#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry)            (entry & 0x00FFFFFF)
163278332Semaste#endif
164278332Semaste
165278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
166278332Semaste#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry)        ((entry >> 24) & 0xFF)
167278332Semaste#endif
168278332Semaste
169278332Semaste#define EXTRACT_BITS(value, mask) \
170278332Semaste        ( (value >> llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \
171288943Sdim          (((1 << llvm::countPopulation(static_cast<uint32_t>(mask))))-1) )
172278332Semaste
173278332Semaste
174278332Semaste
175278332Semaste//----------------------
176309124Sdim// constructor
177278332Semaste//----------------------
178278332Semaste
179309124SdimCompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP &section_sp)
180309124Sdim    : m_objfile(objfile),
181309124Sdim      m_section_sp(section_sp),
182309124Sdim      m_section_contents_if_encrypted(),
183309124Sdim      m_mutex(),
184309124Sdim      m_indexes(),
185309124Sdim      m_indexes_computed(eLazyBoolCalculate),
186309124Sdim      m_unwindinfo_data(),
187309124Sdim      m_unwindinfo_data_computed(false),
188309124Sdim      m_unwind_header()
189278332Semaste{
190278332Semaste}
191278332Semaste
192278332Semaste//----------------------
193278332Semaste// destructor
194278332Semaste//----------------------
195278332Semaste
196278332SemasteCompactUnwindInfo::~CompactUnwindInfo()
197278332Semaste{
198278332Semaste}
199278332Semaste
200278332Semastebool
201278332SemasteCompactUnwindInfo::GetUnwindPlan (Target &target, Address addr, UnwindPlan& unwind_plan)
202278332Semaste{
203278332Semaste    if (!IsValid (target.GetProcessSP()))
204278332Semaste    {
205278332Semaste        return false;
206278332Semaste    }
207278332Semaste    FunctionInfo function_info;
208278332Semaste    if (GetCompactUnwindInfoForFunction (target, addr, function_info))
209278332Semaste    {
210278332Semaste        // shortcut return for functions that have no compact unwind
211278332Semaste        if (function_info.encoding == 0)
212278332Semaste            return false;
213278332Semaste
214278332Semaste        ArchSpec arch;
215278332Semaste        if (m_objfile.GetArchitecture (arch))
216278332Semaste        {
217278332Semaste
218278332Semaste            Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
219278332Semaste            if (log && log->GetVerbose())
220278332Semaste            {
221278332Semaste                StreamString strm;
222309124Sdim                addr.Dump (&strm, NULL, Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments, Address::DumpStyle::DumpStyleFileAddress, arch.GetAddressByteSize());
223278332Semaste                log->Printf ("Got compact unwind encoding 0x%x for function %s", function_info.encoding, strm.GetData());
224278332Semaste            }
225278332Semaste
226278332Semaste            if (function_info.valid_range_offset_start != 0 && function_info.valid_range_offset_end != 0)
227278332Semaste            {
228278332Semaste                SectionList *sl = m_objfile.GetSectionList ();
229278332Semaste                if (sl)
230278332Semaste                {
231309124Sdim                    addr_t func_range_start_file_addr =
232278332Semaste                              function_info.valid_range_offset_start + m_objfile.GetHeaderAddress().GetFileAddress();
233278332Semaste                    AddressRange func_range (func_range_start_file_addr,
234278332Semaste                                      function_info.valid_range_offset_end - function_info.valid_range_offset_start,
235278332Semaste                                      sl);
236278332Semaste                    unwind_plan.SetPlanValidAddressRange (func_range);
237278332Semaste                }
238278332Semaste            }
239278332Semaste
240278332Semaste            if (arch.GetTriple().getArch() == llvm::Triple::x86_64)
241278332Semaste            {
242278332Semaste                return CreateUnwindPlan_x86_64 (target, function_info, unwind_plan, addr);
243278332Semaste            }
244309124Sdim            if (arch.GetTriple().getArch() == llvm::Triple::aarch64)
245309124Sdim            {
246309124Sdim                return CreateUnwindPlan_arm64 (target, function_info, unwind_plan, addr);
247309124Sdim            }
248278332Semaste            if (arch.GetTriple().getArch() == llvm::Triple::x86)
249278332Semaste            {
250278332Semaste                return CreateUnwindPlan_i386 (target, function_info, unwind_plan, addr);
251278332Semaste            }
252309124Sdim            if (arch.GetTriple().getArch() == llvm::Triple::arm || arch.GetTriple().getArch() == llvm::Triple::thumb)
253309124Sdim            {
254309124Sdim                return CreateUnwindPlan_armv7 (target, function_info, unwind_plan, addr);
255309124Sdim            }
256278332Semaste        }
257278332Semaste    }
258278332Semaste    return false;
259278332Semaste}
260278332Semaste
261278332Semastebool
262278332SemasteCompactUnwindInfo::IsValid (const ProcessSP &process_sp)
263278332Semaste{
264278332Semaste    if (m_section_sp.get() == nullptr)
265278332Semaste        return false;
266278332Semaste
267278332Semaste    if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
268278332Semaste        return true;
269278332Semaste
270278332Semaste    ScanIndex (process_sp);
271278332Semaste
272278332Semaste    return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
273278332Semaste}
274278332Semaste
275278332Semastevoid
276278332SemasteCompactUnwindInfo::ScanIndex (const ProcessSP &process_sp)
277278332Semaste{
278309124Sdim    std::lock_guard<std::mutex> guard(m_mutex);
279278332Semaste    if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
280278332Semaste        return;
281278332Semaste
282278332Semaste    // We can't read the index for some reason.
283278332Semaste    if (m_indexes_computed == eLazyBoolNo)
284278332Semaste    {
285278332Semaste        return;
286278332Semaste    }
287278332Semaste
288278332Semaste    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
289278332Semaste    if (log)
290278332Semaste        m_objfile.GetModule()->LogMessage(log, "Reading compact unwind first-level indexes");
291278332Semaste
292278332Semaste    if (m_unwindinfo_data_computed == false)
293278332Semaste    {
294278332Semaste        if (m_section_sp->IsEncrypted())
295278332Semaste        {
296278332Semaste            // Can't get section contents of a protected/encrypted section until we have a live
297278332Semaste            // process and can read them out of memory.
298278332Semaste            if (process_sp.get() == nullptr)
299278332Semaste                return;
300278332Semaste            m_section_contents_if_encrypted.reset (new DataBufferHeap (m_section_sp->GetByteSize(), 0));
301278332Semaste            Error error;
302278332Semaste            if (process_sp->ReadMemory (
303309124Sdim                        m_section_sp->GetLoadBaseAddress (&process_sp->GetTarget()),
304309124Sdim                        m_section_contents_if_encrypted->GetBytes(),
305278332Semaste                        m_section_sp->GetByteSize(), error) == m_section_sp->GetByteSize() && error.Success())
306278332Semaste            {
307278332Semaste                m_unwindinfo_data.SetAddressByteSize (process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
308278332Semaste                m_unwindinfo_data.SetByteOrder (process_sp->GetTarget().GetArchitecture().GetByteOrder());
309278332Semaste                m_unwindinfo_data.SetData (m_section_contents_if_encrypted, 0);
310278332Semaste            }
311278332Semaste        }
312278332Semaste        else
313278332Semaste        {
314278332Semaste            m_objfile.ReadSectionData (m_section_sp.get(), m_unwindinfo_data);
315278332Semaste        }
316278332Semaste        if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
317278332Semaste            return;
318278332Semaste        m_unwindinfo_data_computed = true;
319278332Semaste    }
320278332Semaste
321278332Semaste    if (m_unwindinfo_data.GetByteSize() > 0)
322278332Semaste    {
323278332Semaste        offset_t offset = 0;
324278332Semaste
325278332Semaste                // struct unwind_info_section_header
326278332Semaste                // {
327278332Semaste                // uint32_t    version;            // UNWIND_SECTION_VERSION
328278332Semaste                // uint32_t    commonEncodingsArraySectionOffset;
329278332Semaste                // uint32_t    commonEncodingsArrayCount;
330278332Semaste                // uint32_t    personalityArraySectionOffset;
331278332Semaste                // uint32_t    personalityArrayCount;
332278332Semaste                // uint32_t    indexSectionOffset;
333278332Semaste                // uint32_t    indexCount;
334309124Sdim
335278332Semaste        m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);
336278332Semaste        m_unwind_header.common_encodings_array_offset = m_unwindinfo_data.GetU32(&offset);
337278332Semaste        m_unwind_header.common_encodings_array_count = m_unwindinfo_data.GetU32(&offset);
338278332Semaste        m_unwind_header.personality_array_offset = m_unwindinfo_data.GetU32(&offset);
339278332Semaste        m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);
340278332Semaste        uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);
341278332Semaste
342278332Semaste        uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
343278332Semaste
344288943Sdim        if (m_unwind_header.common_encodings_array_offset > m_unwindinfo_data.GetByteSize()
345288943Sdim            || m_unwind_header.personality_array_offset > m_unwindinfo_data.GetByteSize()
346288943Sdim            || indexSectionOffset > m_unwindinfo_data.GetByteSize()
347288943Sdim            || offset > m_unwindinfo_data.GetByteSize())
348278332Semaste        {
349288943Sdim            Host::SystemLog (Host::eSystemLogError,
350288943Sdim                    "error: Invalid offset encountered in compact unwind info, skipping\n");
351288943Sdim            // don't trust anything from this compact_unwind section if it looks
352296417Sdim            // blatantly invalid data in the header.
353278332Semaste            m_indexes_computed = eLazyBoolNo;
354288943Sdim            return;
355278332Semaste        }
356278332Semaste
357278332Semaste        // Parse the basic information from the indexes
358278332Semaste        // We wait to scan the second level page info until it's needed
359278332Semaste
360309124Sdim            // struct unwind_info_section_header_index_entry
361278332Semaste            // {
362278332Semaste            //     uint32_t        functionOffset;
363278332Semaste            //     uint32_t        secondLevelPagesSectionOffset;
364278332Semaste            //     uint32_t        lsdaIndexArraySectionOffset;
365278332Semaste            // };
366278332Semaste
367309124Sdim        bool clear_address_zeroth_bit = false;
368309124Sdim        ArchSpec arch;
369309124Sdim        if (m_objfile.GetArchitecture (arch))
370309124Sdim        {
371309124Sdim            if (arch.GetTriple().getArch() == llvm::Triple::arm || arch.GetTriple().getArch() == llvm::Triple::thumb)
372309124Sdim                clear_address_zeroth_bit = true;
373309124Sdim        }
374309124Sdim
375278332Semaste        offset = indexSectionOffset;
376278332Semaste        for (uint32_t idx = 0; idx < indexCount; idx++)
377278332Semaste        {
378278332Semaste            uint32_t function_offset = m_unwindinfo_data.GetU32(&offset);      // functionOffset
379278332Semaste            uint32_t second_level_offset = m_unwindinfo_data.GetU32(&offset);  // secondLevelPagesSectionOffset
380278332Semaste            uint32_t lsda_offset = m_unwindinfo_data.GetU32(&offset);          // lsdaIndexArraySectionOffset
381278332Semaste
382278332Semaste            if (second_level_offset > m_section_sp->GetByteSize() || lsda_offset > m_section_sp->GetByteSize())
383278332Semaste            {
384278332Semaste                m_indexes_computed = eLazyBoolNo;
385278332Semaste            }
386278332Semaste
387309124Sdim            if (clear_address_zeroth_bit)
388309124Sdim                function_offset &= ~1ull;
389309124Sdim
390278332Semaste            UnwindIndex this_index;
391309124Sdim            this_index.function_offset = function_offset;
392278332Semaste            this_index.second_level = second_level_offset;
393278332Semaste            this_index.lsda_array_start = lsda_offset;
394278332Semaste
395278332Semaste            if (m_indexes.size() > 0)
396278332Semaste            {
397278332Semaste                m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
398278332Semaste            }
399278332Semaste
400278332Semaste            if (second_level_offset == 0)
401278332Semaste            {
402278332Semaste                this_index.sentinal_entry = true;
403278332Semaste            }
404278332Semaste
405278332Semaste            m_indexes.push_back (this_index);
406278332Semaste        }
407278332Semaste        m_indexes_computed = eLazyBoolYes;
408278332Semaste    }
409278332Semaste    else
410278332Semaste    {
411278332Semaste        m_indexes_computed = eLazyBoolNo;
412278332Semaste    }
413278332Semaste}
414278332Semaste
415278332Semasteuint32_t
416278332SemasteCompactUnwindInfo::GetLSDAForFunctionOffset (uint32_t lsda_offset, uint32_t lsda_count, uint32_t function_offset)
417278332Semaste{
418309124Sdim        // struct unwind_info_section_header_lsda_index_entry
419278332Semaste        // {
420278332Semaste        //         uint32_t        functionOffset;
421278332Semaste        //         uint32_t        lsdaOffset;
422278332Semaste        // };
423278332Semaste
424278332Semaste    offset_t first_entry = lsda_offset;
425278332Semaste    uint32_t low = 0;
426278332Semaste    uint32_t high = lsda_count;
427278332Semaste    while (low < high)
428278332Semaste    {
429278332Semaste        uint32_t mid = (low + high) / 2;
430278332Semaste        offset_t offset = first_entry + (mid * 8);
431278332Semaste        uint32_t mid_func_offset = m_unwindinfo_data.GetU32(&offset);  // functionOffset
432278332Semaste        uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset);  // lsdaOffset
433278332Semaste        if (mid_func_offset == function_offset)
434278332Semaste        {
435278332Semaste            return mid_lsda_offset;
436278332Semaste        }
437278332Semaste        if (mid_func_offset < function_offset)
438278332Semaste        {
439278332Semaste            low = mid + 1;
440278332Semaste        }
441278332Semaste        else
442278332Semaste        {
443278332Semaste            high = mid;
444278332Semaste        }
445278332Semaste    }
446278332Semaste    return 0;
447278332Semaste}
448278332Semaste
449278332Semastelldb::offset_t
450278332SemasteCompactUnwindInfo::BinarySearchRegularSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset)
451278332Semaste{
452278332Semaste    // typedef uint32_t compact_unwind_encoding_t;
453309124Sdim    // struct unwind_info_regular_second_level_entry
454278332Semaste    // {
455278332Semaste    //     uint32_t                    functionOffset;
456278332Semaste    //     compact_unwind_encoding_t    encoding;
457278332Semaste
458278332Semaste    offset_t first_entry = entry_page_offset;
459278332Semaste
460278332Semaste    uint32_t low = 0;
461278332Semaste    uint32_t high = entry_count;
462278332Semaste    uint32_t last = high - 1;
463278332Semaste    while (low < high)
464278332Semaste    {
465278332Semaste        uint32_t mid = (low + high) / 2;
466278332Semaste        offset_t offset = first_entry + (mid * 8);
467278332Semaste        uint32_t mid_func_offset = m_unwindinfo_data.GetU32(&offset);   // functionOffset
468278332Semaste        uint32_t next_func_offset = 0;
469278332Semaste        if (mid < last)
470278332Semaste        {
471278332Semaste            offset = first_entry + ((mid + 1) * 8);
472278332Semaste            next_func_offset = m_unwindinfo_data.GetU32(&offset);       // functionOffset
473278332Semaste        }
474278332Semaste        if (mid_func_offset <= function_offset)
475278332Semaste        {
476278332Semaste            if (mid == last || (next_func_offset > function_offset))
477278332Semaste            {
478278332Semaste                if (entry_func_start_offset)
479278332Semaste                    *entry_func_start_offset = mid_func_offset;
480278332Semaste                if (mid != last && entry_func_end_offset)
481278332Semaste                    *entry_func_end_offset = next_func_offset;
482278332Semaste                return first_entry + (mid * 8);
483278332Semaste            }
484278332Semaste            else
485278332Semaste            {
486278332Semaste                low = mid + 1;
487278332Semaste            }
488278332Semaste        }
489278332Semaste        else
490278332Semaste        {
491278332Semaste            high = mid;
492278332Semaste        }
493278332Semaste    }
494278332Semaste    return LLDB_INVALID_OFFSET;
495278332Semaste}
496278332Semaste
497278332Semasteuint32_t
498278332SemasteCompactUnwindInfo::BinarySearchCompressedSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset_to_find, uint32_t function_offset_base, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset)
499278332Semaste{
500278332Semaste    offset_t first_entry = entry_page_offset;
501278332Semaste
502278332Semaste    uint32_t low = 0;
503278332Semaste    uint32_t high = entry_count;
504278332Semaste    uint32_t last = high - 1;
505278332Semaste    while (low < high)
506278332Semaste    {
507278332Semaste        uint32_t mid = (low + high) / 2;
508278332Semaste        offset_t offset = first_entry + (mid * 4);
509278332Semaste        uint32_t entry = m_unwindinfo_data.GetU32(&offset);   // entry
510278332Semaste        uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (entry);
511278332Semaste        mid_func_offset += function_offset_base;
512278332Semaste        uint32_t next_func_offset = 0;
513278332Semaste        if (mid < last)
514278332Semaste        {
515278332Semaste            offset = first_entry + ((mid + 1) * 4);
516278332Semaste            uint32_t next_entry = m_unwindinfo_data.GetU32(&offset);       // entry
517278332Semaste            next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (next_entry);
518278332Semaste            next_func_offset += function_offset_base;
519278332Semaste        }
520278332Semaste        if (mid_func_offset <= function_offset_to_find)
521278332Semaste        {
522278332Semaste            if (mid == last || (next_func_offset > function_offset_to_find))
523278332Semaste            {
524278332Semaste                if (entry_func_start_offset)
525278332Semaste                    *entry_func_start_offset = mid_func_offset;
526278332Semaste                if (mid != last && entry_func_end_offset)
527278332Semaste                    *entry_func_end_offset = next_func_offset;
528278332Semaste                return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX (entry);
529278332Semaste            }
530278332Semaste            else
531278332Semaste            {
532278332Semaste                low = mid + 1;
533278332Semaste            }
534278332Semaste        }
535278332Semaste        else
536278332Semaste        {
537278332Semaste            high = mid;
538278332Semaste        }
539278332Semaste    }
540278332Semaste
541278332Semaste    return UINT32_MAX;
542278332Semaste}
543278332Semaste
544278332Semastebool
545278332SemasteCompactUnwindInfo::GetCompactUnwindInfoForFunction (Target &target, Address address, FunctionInfo &unwind_info)
546278332Semaste{
547278332Semaste    unwind_info.encoding = 0;
548278332Semaste    unwind_info.lsda_address.Clear();
549278332Semaste    unwind_info.personality_ptr_address.Clear();
550278332Semaste
551278332Semaste    if (!IsValid (target.GetProcessSP()))
552278332Semaste        return false;
553278332Semaste
554278332Semaste    addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
555278332Semaste    SectionList *sl = m_objfile.GetSectionList ();
556278332Semaste    if (sl)
557278332Semaste    {
558278332Semaste        SectionSP text_sect = sl->FindSectionByType (eSectionTypeCode, true);
559278332Semaste        if (text_sect.get())
560278332Semaste        {
561278332Semaste           text_section_file_address = text_sect->GetFileAddress();
562278332Semaste        }
563278332Semaste    }
564278332Semaste    if (text_section_file_address == LLDB_INVALID_ADDRESS)
565278332Semaste        return false;
566278332Semaste
567278332Semaste    addr_t function_offset = address.GetFileAddress() - m_objfile.GetHeaderAddress().GetFileAddress();
568309124Sdim
569278332Semaste    UnwindIndex key;
570278332Semaste    key.function_offset = function_offset;
571309124Sdim
572278332Semaste    std::vector<UnwindIndex>::const_iterator it;
573278332Semaste    it = std::lower_bound (m_indexes.begin(), m_indexes.end(), key);
574278332Semaste    if (it == m_indexes.end())
575278332Semaste    {
576278332Semaste        return false;
577278332Semaste    }
578278332Semaste
579278332Semaste    if (it->function_offset != key.function_offset)
580278332Semaste    {
581278332Semaste        if (it != m_indexes.begin())
582278332Semaste            --it;
583278332Semaste    }
584278332Semaste
585278332Semaste    if (it->sentinal_entry == true)
586278332Semaste    {
587278332Semaste        return false;
588278332Semaste    }
589278332Semaste
590278332Semaste    auto next_it = it + 1;
591288943Sdim    if (next_it != m_indexes.end())
592278332Semaste    {
593309124Sdim        // initialize the function offset end range to be the start of the
594278332Semaste        // next index offset.  If we find an entry which is at the end of
595278332Semaste        // the index table, this will establish the range end.
596278332Semaste        unwind_info.valid_range_offset_end = next_it->function_offset;
597278332Semaste    }
598278332Semaste
599278332Semaste    offset_t second_page_offset = it->second_level;
600278332Semaste    offset_t lsda_array_start = it->lsda_array_start;
601278332Semaste    offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
602278332Semaste
603278332Semaste    offset_t offset = second_page_offset;
604278332Semaste    uint32_t kind = m_unwindinfo_data.GetU32(&offset);  // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED
605278332Semaste
606278332Semaste    if (kind == UNWIND_SECOND_LEVEL_REGULAR)
607278332Semaste    {
608278332Semaste            // struct unwind_info_regular_second_level_page_header
609278332Semaste            // {
610278332Semaste            //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_REGULAR
611278332Semaste            //     uint16_t    entryPageOffset;
612278332Semaste            //     uint16_t    entryCount;
613278332Semaste
614278332Semaste            // typedef uint32_t compact_unwind_encoding_t;
615309124Sdim            // struct unwind_info_regular_second_level_entry
616278332Semaste            // {
617278332Semaste            //     uint32_t                    functionOffset;
618278332Semaste            //     compact_unwind_encoding_t    encoding;
619278332Semaste
620278332Semaste        uint16_t entry_page_offset = m_unwindinfo_data.GetU16(&offset); // entryPageOffset
621278332Semaste        uint16_t entry_count = m_unwindinfo_data.GetU16(&offset);       // entryCount
622278332Semaste
623278332Semaste        offset_t entry_offset = BinarySearchRegularSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset, &unwind_info.valid_range_offset_start, &unwind_info.valid_range_offset_end);
624278332Semaste        if (entry_offset == LLDB_INVALID_OFFSET)
625278332Semaste        {
626278332Semaste            return false;
627278332Semaste        }
628278332Semaste        entry_offset += 4;                                              // skip over functionOffset
629278332Semaste        unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding
630278332Semaste        if (unwind_info.encoding & UNWIND_HAS_LSDA)
631278332Semaste        {
632278332Semaste            SectionList *sl = m_objfile.GetSectionList ();
633278332Semaste            if (sl)
634278332Semaste            {
635278332Semaste                uint32_t lsda_offset = GetLSDAForFunctionOffset (lsda_array_start, lsda_array_count, function_offset);
636278332Semaste                addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
637278332Semaste                unwind_info.lsda_address.ResolveAddressUsingFileSections (objfile_header_file_address + lsda_offset, sl);
638278332Semaste            }
639278332Semaste        }
640278332Semaste        if (unwind_info.encoding & UNWIND_PERSONALITY_MASK)
641278332Semaste        {
642278332Semaste            uint32_t personality_index = EXTRACT_BITS (unwind_info.encoding, UNWIND_PERSONALITY_MASK);
643278332Semaste
644278332Semaste            if (personality_index > 0)
645278332Semaste            {
646278332Semaste                personality_index--;
647278332Semaste                if (personality_index < m_unwind_header.personality_array_count)
648278332Semaste                {
649278332Semaste                    offset_t offset = m_unwind_header.personality_array_offset;
650278332Semaste                    offset += 4 * personality_index;
651278332Semaste                    SectionList *sl = m_objfile.GetSectionList ();
652278332Semaste                    if (sl)
653278332Semaste                    {
654278332Semaste                        uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
655278332Semaste                        addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
656278332Semaste                        unwind_info.personality_ptr_address.ResolveAddressUsingFileSections (objfile_header_file_address + personality_offset, sl);
657278332Semaste                    }
658278332Semaste                }
659278332Semaste            }
660278332Semaste        }
661278332Semaste        return true;
662278332Semaste    }
663278332Semaste    else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED)
664278332Semaste    {
665278332Semaste            // struct unwind_info_compressed_second_level_page_header
666278332Semaste            // {
667278332Semaste            //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_COMPRESSED
668278332Semaste            //     uint16_t    entryPageOffset;         // offset from this 2nd lvl page idx to array of entries
669278332Semaste            //                                          // (an entry has a function offset and index into the encodings)
670309124Sdim            //                                          // NB function offset from the entry in the compressed page
671278332Semaste            //                                          // must be added to the index's functionOffset value.
672309124Sdim            //     uint16_t    entryCount;
673278332Semaste            //     uint16_t    encodingsPageOffset;     // offset from this 2nd lvl page idx to array of encodings
674278332Semaste            //     uint16_t    encodingsCount;
675278332Semaste
676278332Semaste        uint16_t entry_page_offset = m_unwindinfo_data.GetU16(&offset);     // entryPageOffset
677278332Semaste        uint16_t entry_count = m_unwindinfo_data.GetU16(&offset);           // entryCount
678278332Semaste        uint16_t encodings_page_offset = m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
679278332Semaste        uint16_t encodings_count = m_unwindinfo_data.GetU16(&offset);       // encodingsCount
680278332Semaste
681278332Semaste        uint32_t encoding_index = BinarySearchCompressedSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset, it->function_offset, &unwind_info.valid_range_offset_start, &unwind_info.valid_range_offset_end);
682278332Semaste        if (encoding_index == UINT32_MAX || encoding_index >= encodings_count + m_unwind_header.common_encodings_array_count)
683278332Semaste        {
684278332Semaste            return false;
685278332Semaste        }
686278332Semaste        uint32_t encoding = 0;
687278332Semaste        if (encoding_index < m_unwind_header.common_encodings_array_count)
688278332Semaste        {
689278332Semaste            offset = m_unwind_header.common_encodings_array_offset + (encoding_index * sizeof (uint32_t));
690278332Semaste            encoding = m_unwindinfo_data.GetU32(&offset);   // encoding entry from the commonEncodingsArray
691278332Semaste        }
692309124Sdim        else
693278332Semaste        {
694278332Semaste            uint32_t page_specific_entry_index = encoding_index - m_unwind_header.common_encodings_array_count;
695278332Semaste            offset = second_page_offset + encodings_page_offset + (page_specific_entry_index * sizeof (uint32_t));
696278332Semaste            encoding = m_unwindinfo_data.GetU32(&offset);   // encoding entry from the page-specific encoding array
697278332Semaste        }
698278332Semaste        if (encoding == 0)
699278332Semaste            return false;
700278332Semaste
701278332Semaste        unwind_info.encoding = encoding;
702278332Semaste        if (unwind_info.encoding & UNWIND_HAS_LSDA)
703278332Semaste        {
704278332Semaste            SectionList *sl = m_objfile.GetSectionList ();
705278332Semaste            if (sl)
706278332Semaste            {
707278332Semaste                uint32_t lsda_offset = GetLSDAForFunctionOffset (lsda_array_start, lsda_array_count, function_offset);
708278332Semaste                addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
709278332Semaste                unwind_info.lsda_address.ResolveAddressUsingFileSections (objfile_header_file_address + lsda_offset, sl);
710278332Semaste            }
711278332Semaste        }
712278332Semaste        if (unwind_info.encoding & UNWIND_PERSONALITY_MASK)
713278332Semaste        {
714278332Semaste            uint32_t personality_index = EXTRACT_BITS (unwind_info.encoding, UNWIND_PERSONALITY_MASK);
715278332Semaste
716278332Semaste            if (personality_index > 0)
717278332Semaste            {
718278332Semaste                personality_index--;
719278332Semaste                if (personality_index < m_unwind_header.personality_array_count)
720278332Semaste                {
721278332Semaste                    offset_t offset = m_unwind_header.personality_array_offset;
722278332Semaste                    offset += 4 * personality_index;
723278332Semaste                    SectionList *sl = m_objfile.GetSectionList ();
724278332Semaste                    if (sl)
725278332Semaste                    {
726278332Semaste                        uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
727278332Semaste                        addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
728278332Semaste                        unwind_info.personality_ptr_address.ResolveAddressUsingFileSections (objfile_header_file_address + personality_offset, sl);
729278332Semaste                    }
730278332Semaste                }
731278332Semaste            }
732278332Semaste        }
733278332Semaste        return true;
734278332Semaste    }
735278332Semaste    return false;
736278332Semaste}
737278332Semaste
738278332Semasteenum x86_64_eh_regnum {
739278332Semaste    rax = 0,
740278332Semaste    rdx = 1,
741278332Semaste    rcx = 2,
742278332Semaste    rbx = 3,
743278332Semaste    rsi = 4,
744278332Semaste    rdi = 5,
745278332Semaste    rbp = 6,
746278332Semaste    rsp = 7,
747278332Semaste    r8 = 8,
748278332Semaste    r9 = 9,
749278332Semaste    r10 = 10,
750278332Semaste    r11 = 11,
751278332Semaste    r12 = 12,
752278332Semaste    r13 = 13,
753278332Semaste    r14 = 14,
754278332Semaste    r15 = 15,
755278332Semaste    rip = 16   // this is officially the Return Address register number, but close enough
756278332Semaste};
757278332Semaste
758278332Semaste// Convert the compact_unwind_info.h register numbering scheme
759296417Sdim// to eRegisterKindEHFrame (eh_frame) register numbering scheme.
760278332Semasteuint32_t
761278332Semastetranslate_to_eh_frame_regnum_x86_64 (uint32_t unwind_regno)
762278332Semaste{
763278332Semaste    switch (unwind_regno)
764278332Semaste    {
765278332Semaste        case UNWIND_X86_64_REG_RBX:
766278332Semaste            return x86_64_eh_regnum::rbx;
767278332Semaste        case UNWIND_X86_64_REG_R12:
768278332Semaste            return x86_64_eh_regnum::r12;
769278332Semaste        case UNWIND_X86_64_REG_R13:
770278332Semaste            return x86_64_eh_regnum::r13;
771278332Semaste        case UNWIND_X86_64_REG_R14:
772278332Semaste            return x86_64_eh_regnum::r14;
773278332Semaste        case UNWIND_X86_64_REG_R15:
774278332Semaste            return x86_64_eh_regnum::r15;
775278332Semaste        case UNWIND_X86_64_REG_RBP:
776278332Semaste            return x86_64_eh_regnum::rbp;
777278332Semaste        default:
778278332Semaste            return LLDB_INVALID_REGNUM;
779278332Semaste    }
780278332Semaste}
781278332Semaste
782278332Semastebool
783278332SemasteCompactUnwindInfo::CreateUnwindPlan_x86_64 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start)
784278332Semaste{
785278332Semaste    unwind_plan.SetSourceName ("compact unwind info");
786278332Semaste    unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);
787278332Semaste    unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
788296417Sdim    unwind_plan.SetRegisterKind (eRegisterKindEHFrame);
789278332Semaste
790278332Semaste    unwind_plan.SetLSDAAddress (function_info.lsda_address);
791278332Semaste    unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address);
792278332Semaste
793278332Semaste    UnwindPlan::RowSP row (new UnwindPlan::Row);
794278332Semaste
795278332Semaste    const int wordsize = 8;
796278332Semaste    int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
797278332Semaste    switch (mode)
798278332Semaste    {
799278332Semaste        case UNWIND_X86_64_MODE_RBP_FRAME:
800278332Semaste        {
801288943Sdim            row->GetCFAValue().SetIsRegisterPlusOffset (
802288943Sdim                    translate_to_eh_frame_regnum_x86_64 (UNWIND_X86_64_REG_RBP),
803288943Sdim                    2 * wordsize);
804278332Semaste            row->SetOffset (0);
805278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rbp, wordsize * -2, true);
806278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true);
807278332Semaste            row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true);
808309124Sdim
809278332Semaste            uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
810278332Semaste
811278332Semaste            uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
812278332Semaste
813278332Semaste            saved_registers_offset += 2;
814278332Semaste
815278332Semaste            for (int i = 0; i < 5; i++)
816278332Semaste            {
817278332Semaste                uint32_t regnum = saved_registers_locations & 0x7;
818278332Semaste                switch (regnum)
819278332Semaste                {
820278332Semaste                    case UNWIND_X86_64_REG_NONE:
821278332Semaste                        break;
822278332Semaste                    case UNWIND_X86_64_REG_RBX:
823278332Semaste                    case UNWIND_X86_64_REG_R12:
824278332Semaste                    case UNWIND_X86_64_REG_R13:
825278332Semaste                    case UNWIND_X86_64_REG_R14:
826278332Semaste                    case UNWIND_X86_64_REG_R15:
827278332Semaste                        row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (regnum), wordsize * -saved_registers_offset, true);
828278332Semaste                        break;
829278332Semaste                }
830278332Semaste                saved_registers_offset--;
831278332Semaste                saved_registers_locations >>= 3;
832278332Semaste            }
833278332Semaste            unwind_plan.AppendRow (row);
834278332Semaste            return true;
835278332Semaste        }
836278332Semaste        break;
837278332Semaste
838278332Semaste        case UNWIND_X86_64_MODE_STACK_IND:
839278332Semaste        {
840278332Semaste            // The clang in Xcode 6 is emitting incorrect compact unwind encodings for this
841309124Sdim            // style of unwind.  It was fixed in llvm r217020.
842288943Sdim            // The clang in Xcode 7 has this fixed.
843278332Semaste            return false;
844278332Semaste        }
845278332Semaste        break;
846278332Semaste
847278332Semaste        case UNWIND_X86_64_MODE_STACK_IMMD:
848278332Semaste        {
849278332Semaste            uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
850278332Semaste            uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
851278332Semaste            uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
852278332Semaste
853278332Semaste            if (mode == UNWIND_X86_64_MODE_STACK_IND && function_info.valid_range_offset_start != 0)
854278332Semaste            {
855278332Semaste                uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
856278332Semaste
857278332Semaste                // offset into the function instructions; 0 == beginning of first instruction
858278332Semaste                uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
859278332Semaste
860278332Semaste                SectionList *sl = m_objfile.GetSectionList ();
861278332Semaste                if (sl)
862278332Semaste                {
863278332Semaste                    ProcessSP process_sp = target.GetProcessSP();
864278332Semaste                    if (process_sp)
865278332Semaste                    {
866278332Semaste                        Address subl_payload_addr (function_info.valid_range_offset_start, sl);
867278332Semaste                        subl_payload_addr.Slide (offset_to_subl_insn);
868278332Semaste                        Error error;
869278332Semaste                        uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target),
870278332Semaste                                4, 0, error);
871278332Semaste                        if (large_stack_size != 0 && error.Success ())
872278332Semaste                        {
873278332Semaste                            // Got the large stack frame size correctly - use it
874278332Semaste                            stack_size = large_stack_size + (stack_adjust * wordsize);
875278332Semaste                        }
876278332Semaste                        else
877278332Semaste                        {
878278332Semaste                            return false;
879278332Semaste                        }
880278332Semaste                    }
881278332Semaste                    else
882278332Semaste                    {
883278332Semaste                        return false;
884278332Semaste                    }
885278332Semaste                }
886278332Semaste                else
887278332Semaste                {
888278332Semaste                    return false;
889278332Semaste                }
890278332Semaste            }
891278332Semaste
892288943Sdim            int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND ? stack_size : stack_size * wordsize;
893288943Sdim            row->GetCFAValue().SetIsRegisterPlusOffset (x86_64_eh_regnum::rsp, offset);
894288943Sdim
895278332Semaste            row->SetOffset (0);
896278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true);
897278332Semaste            row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true);
898278332Semaste
899278332Semaste            if (register_count > 0)
900278332Semaste            {
901278332Semaste
902278332Semaste                // We need to include (up to) 6 registers in 10 bits.
903278332Semaste                // That would be 18 bits if we just used 3 bits per reg to indicate
904309124Sdim                // the order they're saved on the stack.
905278332Semaste                //
906278332Semaste                // This is done with Lehmer code permutation, e.g. see
907278332Semaste                // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
908288943Sdim                int permunreg[6] = {0, 0, 0, 0, 0, 0};
909278332Semaste
910278332Semaste                // This decodes the variable-base number in the 10 bits
911278332Semaste                // and gives us the Lehmer code sequence which can then
912278332Semaste                // be decoded.
913278332Semaste
914309124Sdim                switch (register_count)
915278332Semaste                {
916278332Semaste                    case 6:
917278332Semaste                        permunreg[0] = permutation/120;    // 120 == 5!
918278332Semaste                        permutation -= (permunreg[0]*120);
919278332Semaste                        permunreg[1] = permutation/24;     // 24 == 4!
920278332Semaste                        permutation -= (permunreg[1]*24);
921278332Semaste                        permunreg[2] = permutation/6;      // 6 == 3!
922278332Semaste                        permutation -= (permunreg[2]*6);
923278332Semaste                        permunreg[3] = permutation/2;      // 2 == 2!
924278332Semaste                        permutation -= (permunreg[3]*2);
925278332Semaste                        permunreg[4] = permutation;        // 1 == 1!
926278332Semaste                        permunreg[5] = 0;
927278332Semaste                        break;
928278332Semaste                    case 5:
929278332Semaste                        permunreg[0] = permutation/120;
930278332Semaste                        permutation -= (permunreg[0]*120);
931278332Semaste                        permunreg[1] = permutation/24;
932278332Semaste                        permutation -= (permunreg[1]*24);
933278332Semaste                        permunreg[2] = permutation/6;
934278332Semaste                        permutation -= (permunreg[2]*6);
935278332Semaste                        permunreg[3] = permutation/2;
936278332Semaste                        permutation -= (permunreg[3]*2);
937278332Semaste                        permunreg[4] = permutation;
938278332Semaste                        break;
939278332Semaste                    case 4:
940278332Semaste                        permunreg[0] = permutation/60;
941278332Semaste                        permutation -= (permunreg[0]*60);
942278332Semaste                        permunreg[1] = permutation/12;
943278332Semaste                        permutation -= (permunreg[1]*12);
944278332Semaste                        permunreg[2] = permutation/3;
945278332Semaste                        permutation -= (permunreg[2]*3);
946278332Semaste                        permunreg[3] = permutation;
947278332Semaste                        break;
948278332Semaste                    case 3:
949278332Semaste                        permunreg[0] = permutation/20;
950278332Semaste                        permutation -= (permunreg[0]*20);
951278332Semaste                        permunreg[1] = permutation/4;
952278332Semaste                        permutation -= (permunreg[1]*4);
953278332Semaste                        permunreg[2] = permutation;
954278332Semaste                        break;
955278332Semaste                    case 2:
956278332Semaste                        permunreg[0] = permutation/5;
957278332Semaste                        permutation -= (permunreg[0]*5);
958278332Semaste                        permunreg[1] = permutation;
959278332Semaste                        break;
960278332Semaste                    case 1:
961278332Semaste                        permunreg[0] = permutation;
962278332Semaste                        break;
963278332Semaste                }
964309124Sdim
965278332Semaste                // Decode the Lehmer code for this permutation of
966278332Semaste                // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
967278332Semaste
968288943Sdim                int registers[6] = { UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE };
969278332Semaste                bool used[7] = { false, false, false, false, false, false, false };
970278332Semaste                for (uint32_t i = 0; i < register_count; i++)
971278332Semaste                {
972278332Semaste                    int renum = 0;
973278332Semaste                    for (int j = 1; j < 7; j++)
974278332Semaste                    {
975278332Semaste                        if (used[j] == false)
976278332Semaste                        {
977278332Semaste                            if (renum == permunreg[i])
978278332Semaste                            {
979278332Semaste                                registers[i] = j;
980278332Semaste                                used[j] = true;
981278332Semaste                                break;
982278332Semaste                            }
983278332Semaste                            renum++;
984278332Semaste                        }
985278332Semaste                    }
986278332Semaste                }
987278332Semaste
988278332Semaste                uint32_t saved_registers_offset = 1;
989278332Semaste                saved_registers_offset++;
990278332Semaste
991278332Semaste                for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
992278332Semaste                {
993278332Semaste                    switch (registers[i])
994278332Semaste                    {
995278332Semaste                        case UNWIND_X86_64_REG_NONE:
996278332Semaste                            break;
997278332Semaste                        case UNWIND_X86_64_REG_RBX:
998278332Semaste                        case UNWIND_X86_64_REG_R12:
999278332Semaste                        case UNWIND_X86_64_REG_R13:
1000278332Semaste                        case UNWIND_X86_64_REG_R14:
1001278332Semaste                        case UNWIND_X86_64_REG_R15:
1002278332Semaste                        case UNWIND_X86_64_REG_RBP:
1003288943Sdim                            row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (registers[i]), wordsize * -saved_registers_offset, true);
1004288943Sdim                            saved_registers_offset++;
1005278332Semaste                        break;
1006278332Semaste                    }
1007278332Semaste                }
1008278332Semaste            }
1009278332Semaste            unwind_plan.AppendRow (row);
1010278332Semaste            return true;
1011278332Semaste        }
1012278332Semaste        break;
1013278332Semaste
1014278332Semaste        case UNWIND_X86_64_MODE_DWARF:
1015278332Semaste        {
1016278332Semaste            return false;
1017278332Semaste        }
1018278332Semaste        break;
1019278332Semaste
1020278332Semaste        case 0:
1021278332Semaste        {
1022278332Semaste            return false;
1023278332Semaste        }
1024278332Semaste        break;
1025278332Semaste    }
1026278332Semaste    return false;
1027278332Semaste}
1028278332Semaste
1029278332Semasteenum i386_eh_regnum {
1030278332Semaste    eax = 0,
1031278332Semaste    ecx = 1,
1032278332Semaste    edx = 2,
1033278332Semaste    ebx = 3,
1034278332Semaste    ebp = 4,
1035278332Semaste    esp = 5,
1036278332Semaste    esi = 6,
1037278332Semaste    edi = 7,
1038278332Semaste    eip = 8    // this is officially the Return Address register number, but close enough
1039278332Semaste};
1040278332Semaste
1041278332Semaste// Convert the compact_unwind_info.h register numbering scheme
1042296417Sdim// to eRegisterKindEHFrame (eh_frame) register numbering scheme.
1043278332Semasteuint32_t
1044278332Semastetranslate_to_eh_frame_regnum_i386 (uint32_t unwind_regno)
1045278332Semaste{
1046278332Semaste    switch (unwind_regno)
1047278332Semaste    {
1048278332Semaste        case UNWIND_X86_REG_EBX:
1049278332Semaste            return i386_eh_regnum::ebx;
1050278332Semaste        case UNWIND_X86_REG_ECX:
1051278332Semaste            return i386_eh_regnum::ecx;
1052278332Semaste        case UNWIND_X86_REG_EDX:
1053278332Semaste            return i386_eh_regnum::edx;
1054278332Semaste        case UNWIND_X86_REG_EDI:
1055278332Semaste            return i386_eh_regnum::edi;
1056278332Semaste        case UNWIND_X86_REG_ESI:
1057278332Semaste            return i386_eh_regnum::esi;
1058278332Semaste        case UNWIND_X86_REG_EBP:
1059278332Semaste            return i386_eh_regnum::ebp;
1060278332Semaste        default:
1061278332Semaste            return LLDB_INVALID_REGNUM;
1062278332Semaste    }
1063278332Semaste}
1064278332Semaste
1065278332Semaste
1066278332Semastebool
1067278332SemasteCompactUnwindInfo::CreateUnwindPlan_i386 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start)
1068278332Semaste{
1069278332Semaste    unwind_plan.SetSourceName ("compact unwind info");
1070278332Semaste    unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);
1071278332Semaste    unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
1072296417Sdim    unwind_plan.SetRegisterKind (eRegisterKindEHFrame);
1073278332Semaste
1074278332Semaste    unwind_plan.SetLSDAAddress (function_info.lsda_address);
1075278332Semaste    unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address);
1076278332Semaste
1077278332Semaste    UnwindPlan::RowSP row (new UnwindPlan::Row);
1078278332Semaste
1079278332Semaste    const int wordsize = 4;
1080278332Semaste    int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
1081278332Semaste    switch (mode)
1082278332Semaste    {
1083278332Semaste        case UNWIND_X86_MODE_EBP_FRAME:
1084278332Semaste        {
1085288943Sdim            row->GetCFAValue().SetIsRegisterPlusOffset (
1086288943Sdim                    translate_to_eh_frame_regnum_i386 (UNWIND_X86_REG_EBP), 2 * wordsize);
1087278332Semaste            row->SetOffset (0);
1088278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::ebp, wordsize * -2, true);
1089278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true);
1090278332Semaste            row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true);
1091309124Sdim
1092278332Semaste            uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
1093278332Semaste
1094278332Semaste            uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
1095278332Semaste
1096278332Semaste            saved_registers_offset += 2;
1097278332Semaste
1098278332Semaste            for (int i = 0; i < 5; i++)
1099278332Semaste            {
1100278332Semaste                uint32_t regnum = saved_registers_locations & 0x7;
1101278332Semaste                switch (regnum)
1102278332Semaste                {
1103278332Semaste                    case UNWIND_X86_REG_NONE:
1104278332Semaste                        break;
1105278332Semaste                    case UNWIND_X86_REG_EBX:
1106278332Semaste                    case UNWIND_X86_REG_ECX:
1107278332Semaste                    case UNWIND_X86_REG_EDX:
1108278332Semaste                    case UNWIND_X86_REG_EDI:
1109278332Semaste                    case UNWIND_X86_REG_ESI:
1110278332Semaste                        row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (regnum), wordsize * -saved_registers_offset, true);
1111278332Semaste                        break;
1112278332Semaste                }
1113278332Semaste                saved_registers_offset--;
1114278332Semaste                saved_registers_locations >>= 3;
1115278332Semaste            }
1116278332Semaste            unwind_plan.AppendRow (row);
1117278332Semaste            return true;
1118278332Semaste        }
1119278332Semaste        break;
1120278332Semaste
1121278332Semaste        case UNWIND_X86_MODE_STACK_IND:
1122278332Semaste        case UNWIND_X86_MODE_STACK_IMMD:
1123278332Semaste        {
1124278332Semaste            uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1125278332Semaste            uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
1126278332Semaste            uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
1127278332Semaste
1128278332Semaste            if (mode == UNWIND_X86_MODE_STACK_IND && function_info.valid_range_offset_start != 0)
1129278332Semaste            {
1130278332Semaste                uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
1131278332Semaste
1132278332Semaste                // offset into the function instructions; 0 == beginning of first instruction
1133278332Semaste                uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1134278332Semaste
1135278332Semaste                SectionList *sl = m_objfile.GetSectionList ();
1136278332Semaste                if (sl)
1137278332Semaste                {
1138278332Semaste                    ProcessSP process_sp = target.GetProcessSP();
1139278332Semaste                    if (process_sp)
1140278332Semaste                    {
1141278332Semaste                        Address subl_payload_addr (function_info.valid_range_offset_start, sl);
1142278332Semaste                        subl_payload_addr.Slide (offset_to_subl_insn);
1143278332Semaste                        Error error;
1144278332Semaste                        uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target),
1145278332Semaste                                4, 0, error);
1146278332Semaste                        if (large_stack_size != 0 && error.Success ())
1147278332Semaste                        {
1148278332Semaste                            // Got the large stack frame size correctly - use it
1149278332Semaste                            stack_size = large_stack_size + (stack_adjust * wordsize);
1150278332Semaste                        }
1151278332Semaste                        else
1152278332Semaste                        {
1153278332Semaste                            return false;
1154278332Semaste                        }
1155278332Semaste                    }
1156278332Semaste                    else
1157278332Semaste                    {
1158278332Semaste                        return false;
1159278332Semaste                    }
1160278332Semaste                }
1161278332Semaste                else
1162278332Semaste                {
1163278332Semaste                    return false;
1164278332Semaste                }
1165278332Semaste            }
1166278332Semaste
1167288943Sdim            int32_t offset = mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
1168288943Sdim            row->GetCFAValue().SetIsRegisterPlusOffset (i386_eh_regnum::esp, offset);
1169278332Semaste            row->SetOffset (0);
1170278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true);
1171278332Semaste            row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true);
1172309124Sdim
1173278332Semaste            if (register_count > 0)
1174278332Semaste            {
1175278332Semaste
1176278332Semaste                // We need to include (up to) 6 registers in 10 bits.
1177278332Semaste                // That would be 18 bits if we just used 3 bits per reg to indicate
1178309124Sdim                // the order they're saved on the stack.
1179278332Semaste                //
1180278332Semaste                // This is done with Lehmer code permutation, e.g. see
1181278332Semaste                // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
1182288943Sdim                int permunreg[6] = {0, 0, 0, 0, 0, 0};
1183278332Semaste
1184278332Semaste                // This decodes the variable-base number in the 10 bits
1185278332Semaste                // and gives us the Lehmer code sequence which can then
1186278332Semaste                // be decoded.
1187278332Semaste
1188309124Sdim                switch (register_count)
1189278332Semaste                {
1190278332Semaste                    case 6:
1191278332Semaste                        permunreg[0] = permutation/120;    // 120 == 5!
1192278332Semaste                        permutation -= (permunreg[0]*120);
1193278332Semaste                        permunreg[1] = permutation/24;     // 24 == 4!
1194278332Semaste                        permutation -= (permunreg[1]*24);
1195278332Semaste                        permunreg[2] = permutation/6;      // 6 == 3!
1196278332Semaste                        permutation -= (permunreg[2]*6);
1197278332Semaste                        permunreg[3] = permutation/2;      // 2 == 2!
1198278332Semaste                        permutation -= (permunreg[3]*2);
1199278332Semaste                        permunreg[4] = permutation;        // 1 == 1!
1200278332Semaste                        permunreg[5] = 0;
1201278332Semaste                        break;
1202278332Semaste                    case 5:
1203278332Semaste                        permunreg[0] = permutation/120;
1204278332Semaste                        permutation -= (permunreg[0]*120);
1205278332Semaste                        permunreg[1] = permutation/24;
1206278332Semaste                        permutation -= (permunreg[1]*24);
1207278332Semaste                        permunreg[2] = permutation/6;
1208278332Semaste                        permutation -= (permunreg[2]*6);
1209278332Semaste                        permunreg[3] = permutation/2;
1210278332Semaste                        permutation -= (permunreg[3]*2);
1211278332Semaste                        permunreg[4] = permutation;
1212278332Semaste                        break;
1213278332Semaste                    case 4:
1214278332Semaste                        permunreg[0] = permutation/60;
1215278332Semaste                        permutation -= (permunreg[0]*60);
1216278332Semaste                        permunreg[1] = permutation/12;
1217278332Semaste                        permutation -= (permunreg[1]*12);
1218278332Semaste                        permunreg[2] = permutation/3;
1219278332Semaste                        permutation -= (permunreg[2]*3);
1220278332Semaste                        permunreg[3] = permutation;
1221278332Semaste                        break;
1222278332Semaste                    case 3:
1223278332Semaste                        permunreg[0] = permutation/20;
1224278332Semaste                        permutation -= (permunreg[0]*20);
1225278332Semaste                        permunreg[1] = permutation/4;
1226278332Semaste                        permutation -= (permunreg[1]*4);
1227278332Semaste                        permunreg[2] = permutation;
1228278332Semaste                        break;
1229278332Semaste                    case 2:
1230278332Semaste                        permunreg[0] = permutation/5;
1231278332Semaste                        permutation -= (permunreg[0]*5);
1232278332Semaste                        permunreg[1] = permutation;
1233278332Semaste                        break;
1234278332Semaste                    case 1:
1235278332Semaste                        permunreg[0] = permutation;
1236278332Semaste                        break;
1237278332Semaste                }
1238309124Sdim
1239278332Semaste                // Decode the Lehmer code for this permutation of
1240278332Semaste                // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
1241278332Semaste
1242288943Sdim                int registers[6] = { UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE };
1243278332Semaste                bool used[7] = { false, false, false, false, false, false, false };
1244278332Semaste                for (uint32_t i = 0; i < register_count; i++)
1245278332Semaste                {
1246278332Semaste                    int renum = 0;
1247278332Semaste                    for (int j = 1; j < 7; j++)
1248278332Semaste                    {
1249278332Semaste                        if (used[j] == false)
1250278332Semaste                        {
1251278332Semaste                            if (renum == permunreg[i])
1252278332Semaste                            {
1253278332Semaste                                registers[i] = j;
1254278332Semaste                                used[j] = true;
1255278332Semaste                                break;
1256278332Semaste                            }
1257278332Semaste                            renum++;
1258278332Semaste                        }
1259278332Semaste                    }
1260278332Semaste                }
1261278332Semaste
1262278332Semaste                uint32_t saved_registers_offset = 1;
1263278332Semaste                saved_registers_offset++;
1264278332Semaste
1265278332Semaste                for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
1266278332Semaste                {
1267278332Semaste                    switch (registers[i])
1268278332Semaste                    {
1269278332Semaste                        case UNWIND_X86_REG_NONE:
1270278332Semaste                            break;
1271278332Semaste                        case UNWIND_X86_REG_EBX:
1272278332Semaste                        case UNWIND_X86_REG_ECX:
1273278332Semaste                        case UNWIND_X86_REG_EDX:
1274278332Semaste                        case UNWIND_X86_REG_EDI:
1275278332Semaste                        case UNWIND_X86_REG_ESI:
1276278332Semaste                        case UNWIND_X86_REG_EBP:
1277288943Sdim                            row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (registers[i]), wordsize * -saved_registers_offset, true);
1278288943Sdim                            saved_registers_offset++;
1279278332Semaste                        break;
1280278332Semaste                    }
1281278332Semaste                }
1282278332Semaste            }
1283278332Semaste
1284278332Semaste            unwind_plan.AppendRow (row);
1285278332Semaste            return true;
1286278332Semaste        }
1287278332Semaste        break;
1288278332Semaste
1289278332Semaste        case UNWIND_X86_MODE_DWARF:
1290278332Semaste        {
1291278332Semaste            return false;
1292278332Semaste        }
1293278332Semaste        break;
1294278332Semaste    }
1295278332Semaste    return false;
1296278332Semaste}
1297309124Sdim
1298309124Sdim
1299309124Sdim
1300309124Sdim// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)" doc by ARM
1301309124Sdim
1302309124Sdimenum arm64_eh_regnum {
1303309124Sdim    x19 = 19,
1304309124Sdim    x20 = 20,
1305309124Sdim    x21 = 21,
1306309124Sdim    x22 = 22,
1307309124Sdim    x23 = 23,
1308309124Sdim    x24 = 24,
1309309124Sdim    x25 = 25,
1310309124Sdim    x26 = 26,
1311309124Sdim    x27 = 27,
1312309124Sdim    x28 = 28,
1313309124Sdim
1314309124Sdim    fp = 29,
1315309124Sdim    ra = 30,
1316309124Sdim    sp = 31,
1317309124Sdim    pc = 32,
1318309124Sdim
1319309124Sdim    // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s for the 64-bit
1320309124Sdim    // fp regs.  Normally in DWARF it's context sensitive - so it knows it is fetching a
1321309124Sdim    // 32- or 64-bit quantity from reg v8 to indicate s0 or d0 - but the unwinder is operating
1322309124Sdim    // at a lower level and we'd try to fetch 128 bits if we were told that v8 were stored on
1323309124Sdim    // the stack...
1324309124Sdim    v8  = 72,
1325309124Sdim    v9  = 73,
1326309124Sdim    v10 = 74,
1327309124Sdim    v11 = 75,
1328309124Sdim    v12 = 76,
1329309124Sdim    v13 = 77,
1330309124Sdim    v14 = 78,
1331309124Sdim    v15 = 79,
1332309124Sdim};
1333309124Sdim
1334309124Sdimenum arm_eh_regnum {
1335309124Sdim    arm_r0 = 0,
1336309124Sdim    arm_r1 = 1,
1337309124Sdim    arm_r2 = 2,
1338309124Sdim    arm_r3 = 3,
1339309124Sdim    arm_r4 = 4,
1340309124Sdim    arm_r5 = 5,
1341309124Sdim    arm_r6 = 6,
1342309124Sdim    arm_r7 = 7,
1343309124Sdim    arm_r8 = 8,
1344309124Sdim    arm_r9 = 9,
1345309124Sdim    arm_r10 = 10,
1346309124Sdim    arm_r11 = 11,
1347309124Sdim    arm_r12 = 12,
1348309124Sdim
1349309124Sdim    arm_sp = 13,
1350309124Sdim    arm_lr = 14,
1351309124Sdim    arm_pc = 15,
1352309124Sdim
1353309124Sdim    arm_d0 = 256,
1354309124Sdim    arm_d1 = 257,
1355309124Sdim    arm_d2 = 258,
1356309124Sdim    arm_d3 = 259,
1357309124Sdim    arm_d4 = 260,
1358309124Sdim    arm_d5 = 261,
1359309124Sdim    arm_d6 = 262,
1360309124Sdim    arm_d7 = 263,
1361309124Sdim    arm_d8 = 264,
1362309124Sdim    arm_d9 = 265,
1363309124Sdim    arm_d10 = 266,
1364309124Sdim    arm_d11 = 267,
1365309124Sdim    arm_d12 = 268,
1366309124Sdim    arm_d13 = 269,
1367309124Sdim    arm_d14 = 270,
1368309124Sdim};
1369309124Sdim
1370309124Sdim
1371309124Sdim
1372309124Sdimbool
1373309124SdimCompactUnwindInfo::CreateUnwindPlan_arm64 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start)
1374309124Sdim{
1375309124Sdim    unwind_plan.SetSourceName ("compact unwind info");
1376309124Sdim    unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);
1377309124Sdim    unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
1378309124Sdim    unwind_plan.SetRegisterKind (eRegisterKindEHFrame);
1379309124Sdim
1380309124Sdim    unwind_plan.SetLSDAAddress (function_info.lsda_address);
1381309124Sdim    unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address);
1382309124Sdim
1383309124Sdim    UnwindPlan::RowSP row (new UnwindPlan::Row);
1384309124Sdim
1385309124Sdim    const int wordsize = 8;
1386309124Sdim    int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;
1387309124Sdim
1388309124Sdim    if (mode == UNWIND_ARM64_MODE_DWARF)
1389309124Sdim        return false;
1390309124Sdim
1391309124Sdim    if (mode == UNWIND_ARM64_MODE_FRAMELESS)
1392309124Sdim    {
1393309124Sdim        row->SetOffset (0);
1394309124Sdim
1395309124Sdim        uint32_t stack_size = (EXTRACT_BITS (function_info.encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) * 16;
1396309124Sdim
1397309124Sdim        // Our previous Call Frame Address is the stack pointer plus the stack size
1398309124Sdim        row->GetCFAValue().SetIsRegisterPlusOffset (arm64_eh_regnum::sp, stack_size);
1399309124Sdim
1400309124Sdim        // Our previous PC is in the LR
1401309124Sdim        row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra, true);
1402309124Sdim
1403309124Sdim        unwind_plan.AppendRow (row);
1404309124Sdim        return true;
1405309124Sdim    }
1406309124Sdim
1407309124Sdim    // Should not be possible
1408309124Sdim    if (mode != UNWIND_ARM64_MODE_FRAME)
1409309124Sdim        return false;
1410309124Sdim
1411309124Sdim
1412309124Sdim    // mode == UNWIND_ARM64_MODE_FRAME
1413309124Sdim
1414309124Sdim    row->GetCFAValue().SetIsRegisterPlusOffset (arm64_eh_regnum::fp , 2 * wordsize);
1415309124Sdim    row->SetOffset (0);
1416309124Sdim    row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::fp, wordsize * -2, true);
1417309124Sdim    row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::pc, wordsize * -1, true);
1418309124Sdim    row->SetRegisterLocationToIsCFAPlusOffset (arm64_eh_regnum::sp, 0, true);
1419309124Sdim
1420309124Sdim    int reg_pairs_saved_count = 1;
1421309124Sdim
1422309124Sdim    uint32_t saved_register_bits = function_info.encoding & 0xfff;
1423309124Sdim
1424309124Sdim    if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR)
1425309124Sdim    {
1426309124Sdim        int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1427309124Sdim        cfa_offset -= wordsize;
1428309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x19, cfa_offset, true);
1429309124Sdim        cfa_offset -= wordsize;
1430309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x20, cfa_offset, true);
1431309124Sdim        reg_pairs_saved_count++;
1432309124Sdim    }
1433309124Sdim
1434309124Sdim    if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR)
1435309124Sdim    {
1436309124Sdim        int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1437309124Sdim        cfa_offset -= wordsize;
1438309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x21, cfa_offset, true);
1439309124Sdim        cfa_offset -= wordsize;
1440309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x22, cfa_offset, true);
1441309124Sdim        reg_pairs_saved_count++;
1442309124Sdim    }
1443309124Sdim
1444309124Sdim    if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR)
1445309124Sdim    {
1446309124Sdim        int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1447309124Sdim        cfa_offset -= wordsize;
1448309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x23, cfa_offset, true);
1449309124Sdim        cfa_offset -= wordsize;
1450309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x24, cfa_offset, true);
1451309124Sdim        reg_pairs_saved_count++;
1452309124Sdim    }
1453309124Sdim
1454309124Sdim    if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR)
1455309124Sdim    {
1456309124Sdim        int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1457309124Sdim        cfa_offset -= wordsize;
1458309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x25, cfa_offset, true);
1459309124Sdim        cfa_offset -= wordsize;
1460309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x26, cfa_offset, true);
1461309124Sdim        reg_pairs_saved_count++;
1462309124Sdim    }
1463309124Sdim
1464309124Sdim    if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR)
1465309124Sdim    {
1466309124Sdim        int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1467309124Sdim        cfa_offset -= wordsize;
1468309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x27, cfa_offset, true);
1469309124Sdim        cfa_offset -= wordsize;
1470309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x28, cfa_offset, true);
1471309124Sdim        reg_pairs_saved_count++;
1472309124Sdim    }
1473309124Sdim
1474309124Sdim    // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits off the stack;
1475309124Sdim    // not sure if we have a good way to represent the 64-bitness of these saves.
1476309124Sdim
1477309124Sdim    if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR)
1478309124Sdim    {
1479309124Sdim        reg_pairs_saved_count++;
1480309124Sdim    }
1481309124Sdim    if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR)
1482309124Sdim    {
1483309124Sdim        reg_pairs_saved_count++;
1484309124Sdim    }
1485309124Sdim    if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR)
1486309124Sdim    {
1487309124Sdim        reg_pairs_saved_count++;
1488309124Sdim    }
1489309124Sdim    if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR)
1490309124Sdim    {
1491309124Sdim        reg_pairs_saved_count++;
1492309124Sdim    }
1493309124Sdim
1494309124Sdim    unwind_plan.AppendRow (row);
1495309124Sdim    return true;
1496309124Sdim}
1497309124Sdim
1498309124Sdimbool
1499309124SdimCompactUnwindInfo::CreateUnwindPlan_armv7 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start)
1500309124Sdim{
1501309124Sdim    unwind_plan.SetSourceName ("compact unwind info");
1502309124Sdim    unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);
1503309124Sdim    unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
1504309124Sdim    unwind_plan.SetRegisterKind (eRegisterKindEHFrame);
1505309124Sdim
1506309124Sdim    unwind_plan.SetLSDAAddress (function_info.lsda_address);
1507309124Sdim    unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address);
1508309124Sdim
1509309124Sdim    UnwindPlan::RowSP row (new UnwindPlan::Row);
1510309124Sdim
1511309124Sdim    const int wordsize = 4;
1512309124Sdim    int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;
1513309124Sdim
1514309124Sdim    if (mode == UNWIND_ARM_MODE_DWARF)
1515309124Sdim        return false;
1516309124Sdim
1517309124Sdim    uint32_t stack_adjust = (EXTRACT_BITS (function_info.encoding, UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) * wordsize;
1518309124Sdim
1519309124Sdim    row->GetCFAValue().SetIsRegisterPlusOffset (arm_r7 , (2 * wordsize) + stack_adjust);
1520309124Sdim    row->SetOffset (0);
1521309124Sdim    row->SetRegisterLocationToAtCFAPlusOffset (arm_r7, (wordsize * -2) - stack_adjust, true);
1522309124Sdim    row->SetRegisterLocationToAtCFAPlusOffset (arm_pc, (wordsize * -1) - stack_adjust, true);
1523309124Sdim    row->SetRegisterLocationToIsCFAPlusOffset (arm_sp, 0, true);
1524309124Sdim
1525309124Sdim    int cfa_offset = -stack_adjust - (2 * wordsize);
1526309124Sdim
1527309124Sdim    uint32_t saved_register_bits = function_info.encoding & 0xff;
1528309124Sdim
1529309124Sdim    if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6)
1530309124Sdim    {
1531309124Sdim        cfa_offset -= wordsize;
1532309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm_r6, cfa_offset, true);
1533309124Sdim    }
1534309124Sdim
1535309124Sdim    if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5)
1536309124Sdim    {
1537309124Sdim        cfa_offset -= wordsize;
1538309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm_r5, cfa_offset, true);
1539309124Sdim    }
1540309124Sdim
1541309124Sdim    if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4)
1542309124Sdim    {
1543309124Sdim        cfa_offset -= wordsize;
1544309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm_r4, cfa_offset, true);
1545309124Sdim    }
1546309124Sdim
1547309124Sdim    if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12)
1548309124Sdim    {
1549309124Sdim        cfa_offset -= wordsize;
1550309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm_r12, cfa_offset, true);
1551309124Sdim    }
1552309124Sdim
1553309124Sdim    if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11)
1554309124Sdim    {
1555309124Sdim        cfa_offset -= wordsize;
1556309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm_r11, cfa_offset, true);
1557309124Sdim    }
1558309124Sdim
1559309124Sdim    if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10)
1560309124Sdim    {
1561309124Sdim        cfa_offset -= wordsize;
1562309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm_r10, cfa_offset, true);
1563309124Sdim    }
1564309124Sdim
1565309124Sdim    if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9)
1566309124Sdim    {
1567309124Sdim        cfa_offset -= wordsize;
1568309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm_r9, cfa_offset, true);
1569309124Sdim    }
1570309124Sdim
1571309124Sdim    if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8)
1572309124Sdim    {
1573309124Sdim        cfa_offset -= wordsize;
1574309124Sdim        row->SetRegisterLocationToAtCFAPlusOffset (arm_r8, cfa_offset, true);
1575309124Sdim    }
1576309124Sdim
1577309124Sdim
1578309124Sdim    if (mode == UNWIND_ARM_MODE_FRAME_D)
1579309124Sdim    {
1580309124Sdim        uint32_t d_reg_bits = EXTRACT_BITS (function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
1581309124Sdim        switch (d_reg_bits)
1582309124Sdim        {
1583309124Sdim            case 0:
1584309124Sdim                // vpush {d8}
1585309124Sdim                cfa_offset -= 8;
1586309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d8, cfa_offset, true);
1587309124Sdim                break;
1588309124Sdim            case 1:
1589309124Sdim                // vpush {d10}
1590309124Sdim                // vpush {d8}
1591309124Sdim                cfa_offset -= 8;
1592309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d10, cfa_offset, true);
1593309124Sdim                cfa_offset -= 8;
1594309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d8, cfa_offset, true);
1595309124Sdim                break;
1596309124Sdim            case 2:
1597309124Sdim                // vpush {d12}
1598309124Sdim                // vpush {d10}
1599309124Sdim                // vpush {d8}
1600309124Sdim                cfa_offset -= 8;
1601309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d12, cfa_offset, true);
1602309124Sdim                cfa_offset -= 8;
1603309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d10, cfa_offset, true);
1604309124Sdim                cfa_offset -= 8;
1605309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d8, cfa_offset, true);
1606309124Sdim                break;
1607309124Sdim            case 3:
1608309124Sdim                // vpush {d14}
1609309124Sdim                // vpush {d12}
1610309124Sdim                // vpush {d10}
1611309124Sdim                // vpush {d8}
1612309124Sdim                cfa_offset -= 8;
1613309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d14, cfa_offset, true);
1614309124Sdim                cfa_offset -= 8;
1615309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d12, cfa_offset, true);
1616309124Sdim                cfa_offset -= 8;
1617309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d10, cfa_offset, true);
1618309124Sdim                cfa_offset -= 8;
1619309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d8, cfa_offset, true);
1620309124Sdim                break;
1621309124Sdim            case 4:
1622309124Sdim                // vpush {d14}
1623309124Sdim                // vpush {d12}
1624309124Sdim                // sp = (sp - 24) & (-16);
1625309124Sdim                // vst   {d8, d9, d10}
1626309124Sdim                cfa_offset -= 8;
1627309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d14, cfa_offset, true);
1628309124Sdim                cfa_offset -= 8;
1629309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d12, cfa_offset, true);
1630309124Sdim
1631309124Sdim                // FIXME we don't have a way to represent reg saves at an specific alignment short of
1632309124Sdim                // coming up with some DWARF location description.
1633309124Sdim
1634309124Sdim                break;
1635309124Sdim            case 5:
1636309124Sdim                // vpush {d14}
1637309124Sdim                // sp = (sp - 40) & (-16);
1638309124Sdim                // vst   {d8, d9, d10, d11}
1639309124Sdim                // vst   {d12}
1640309124Sdim
1641309124Sdim                cfa_offset -= 8;
1642309124Sdim                row->SetRegisterLocationToAtCFAPlusOffset (arm_d14, cfa_offset, true);
1643309124Sdim
1644309124Sdim                // FIXME we don't have a way to represent reg saves at an specific alignment short of
1645309124Sdim                // coming up with some DWARF location description.
1646309124Sdim
1647309124Sdim                break;
1648309124Sdim            case 6:
1649309124Sdim                // sp = (sp - 56) & (-16);
1650309124Sdim                // vst   {d8, d9, d10, d11}
1651309124Sdim                // vst   {d12, d13, d14}
1652309124Sdim
1653309124Sdim                // FIXME we don't have a way to represent reg saves at an specific alignment short of
1654309124Sdim                // coming up with some DWARF location description.
1655309124Sdim
1656309124Sdim                break;
1657309124Sdim            case 7:
1658309124Sdim                // sp = (sp - 64) & (-16);
1659309124Sdim                // vst   {d8, d9, d10, d11}
1660309124Sdim                // vst   {d12, d13, d14, d15}
1661309124Sdim
1662309124Sdim                // FIXME we don't have a way to represent reg saves at an specific alignment short of
1663309124Sdim                // coming up with some DWARF location description.
1664309124Sdim
1665309124Sdim                break;
1666309124Sdim        }
1667309124Sdim    }
1668309124Sdim
1669309124Sdim    unwind_plan.AppendRow (row);
1670309124Sdim    return true;
1671309124Sdim}
1672309124Sdim
1673309124Sdim
1674