CompactUnwindInfo.cpp revision 278332
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"
16278332Semaste#include "lldb/Core/Log.h"
17278332Semaste#include "lldb/Core/Module.h"
18278332Semaste#include "lldb/Core/Section.h"
19278332Semaste#include "lldb/Core/Section.h"
20278332Semaste#include "lldb/Core/StreamString.h"
21278332Semaste#include "lldb/Symbol/CompactUnwindInfo.h"
22278332Semaste#include "lldb/Symbol/ObjectFile.h"
23278332Semaste#include "lldb/Symbol/UnwindPlan.h"
24278332Semaste#include "lldb/Target/Process.h"
25278332Semaste#include "lldb/Target/Target.h"
26278332Semaste
27278332Semaste#include "llvm/Support/MathExtras.h"
28278332Semaste
29278332Semasteusing namespace lldb;
30278332Semasteusing namespace lldb_private;
31278332Semaste
32278332Semaste
33278332Semastenamespace lldb_private {
34278332Semaste
35278332Semaste    // Constants from <mach-o/compact_unwind_encoding.h>
36278332Semaste
37278332Semaste    enum {
38278332Semaste        UNWIND_IS_NOT_FUNCTION_START           = 0x80000000,
39278332Semaste        UNWIND_HAS_LSDA                        = 0x40000000,
40278332Semaste        UNWIND_PERSONALITY_MASK                = 0x30000000,
41278332Semaste    };
42278332Semaste
43278332Semaste    enum {
44278332Semaste        UNWIND_X86_MODE_MASK                         = 0x0F000000,
45278332Semaste        UNWIND_X86_MODE_EBP_FRAME                    = 0x01000000,
46278332Semaste        UNWIND_X86_MODE_STACK_IMMD                   = 0x02000000,
47278332Semaste        UNWIND_X86_MODE_STACK_IND                    = 0x03000000,
48278332Semaste        UNWIND_X86_MODE_DWARF                        = 0x04000000,
49278332Semaste
50278332Semaste        UNWIND_X86_EBP_FRAME_REGISTERS               = 0x00007FFF,
51278332Semaste        UNWIND_X86_EBP_FRAME_OFFSET                  = 0x00FF0000,
52278332Semaste
53278332Semaste        UNWIND_X86_FRAMELESS_STACK_SIZE              = 0x00FF0000,
54278332Semaste        UNWIND_X86_FRAMELESS_STACK_ADJUST            = 0x0000E000,
55278332Semaste        UNWIND_X86_FRAMELESS_STACK_REG_COUNT         = 0x00001C00,
56278332Semaste        UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION   = 0x000003FF,
57278332Semaste
58278332Semaste        UNWIND_X86_DWARF_SECTION_OFFSET              = 0x00FFFFFF,
59278332Semaste    };
60278332Semaste
61278332Semaste    enum {
62278332Semaste        UNWIND_X86_REG_NONE     = 0,
63278332Semaste        UNWIND_X86_REG_EBX      = 1,
64278332Semaste        UNWIND_X86_REG_ECX      = 2,
65278332Semaste        UNWIND_X86_REG_EDX      = 3,
66278332Semaste        UNWIND_X86_REG_EDI      = 4,
67278332Semaste        UNWIND_X86_REG_ESI      = 5,
68278332Semaste        UNWIND_X86_REG_EBP      = 6,
69278332Semaste    };
70278332Semaste    enum {
71278332Semaste        UNWIND_X86_64_MODE_MASK                         = 0x0F000000,
72278332Semaste        UNWIND_X86_64_MODE_RBP_FRAME                    = 0x01000000,
73278332Semaste        UNWIND_X86_64_MODE_STACK_IMMD                   = 0x02000000,
74278332Semaste        UNWIND_X86_64_MODE_STACK_IND                    = 0x03000000,
75278332Semaste        UNWIND_X86_64_MODE_DWARF                        = 0x04000000,
76278332Semaste
77278332Semaste        UNWIND_X86_64_RBP_FRAME_REGISTERS               = 0x00007FFF,
78278332Semaste        UNWIND_X86_64_RBP_FRAME_OFFSET                  = 0x00FF0000,
79278332Semaste
80278332Semaste        UNWIND_X86_64_FRAMELESS_STACK_SIZE              = 0x00FF0000,
81278332Semaste        UNWIND_X86_64_FRAMELESS_STACK_ADJUST            = 0x0000E000,
82278332Semaste        UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT         = 0x00001C00,
83278332Semaste        UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION   = 0x000003FF,
84278332Semaste
85278332Semaste        UNWIND_X86_64_DWARF_SECTION_OFFSET              = 0x00FFFFFF,
86278332Semaste    };
87278332Semaste
88278332Semaste    enum {
89278332Semaste        UNWIND_X86_64_REG_NONE       = 0,
90278332Semaste        UNWIND_X86_64_REG_RBX        = 1,
91278332Semaste        UNWIND_X86_64_REG_R12        = 2,
92278332Semaste        UNWIND_X86_64_REG_R13        = 3,
93278332Semaste        UNWIND_X86_64_REG_R14        = 4,
94278332Semaste        UNWIND_X86_64_REG_R15        = 5,
95278332Semaste        UNWIND_X86_64_REG_RBP        = 6,
96278332Semaste    };
97278332Semaste};
98278332Semaste
99278332Semaste
100278332Semaste#ifndef UNWIND_SECOND_LEVEL_REGULAR
101278332Semaste#define UNWIND_SECOND_LEVEL_REGULAR 2
102278332Semaste#endif
103278332Semaste
104278332Semaste#ifndef UNWIND_SECOND_LEVEL_COMPRESSED
105278332Semaste#define UNWIND_SECOND_LEVEL_COMPRESSED 3
106278332Semaste#endif
107278332Semaste
108278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
109278332Semaste#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry)            (entry & 0x00FFFFFF)
110278332Semaste#endif
111278332Semaste
112278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
113278332Semaste#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry)        ((entry >> 24) & 0xFF)
114278332Semaste#endif
115278332Semaste
116278332Semaste#define EXTRACT_BITS(value, mask) \
117278332Semaste        ( (value >> llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \
118278332Semaste          (((1 << llvm::CountPopulation_32(static_cast<uint32_t>(mask))))-1) )
119278332Semaste
120278332Semaste
121278332Semaste
122278332Semaste//----------------------
123278332Semaste// constructor
124278332Semaste//----------------------
125278332Semaste
126278332Semaste
127278332SemasteCompactUnwindInfo::CompactUnwindInfo(ObjectFile& objfile, SectionSP& section_sp) :
128278332Semaste    m_objfile (objfile),
129278332Semaste    m_section_sp (section_sp),
130278332Semaste    m_section_contents_if_encrypted (),
131278332Semaste    m_mutex (),
132278332Semaste    m_indexes (),
133278332Semaste    m_indexes_computed (eLazyBoolCalculate),
134278332Semaste    m_unwindinfo_data (),
135278332Semaste    m_unwindinfo_data_computed (false),
136278332Semaste    m_unwind_header ()
137278332Semaste{
138278332Semaste
139278332Semaste}
140278332Semaste
141278332Semaste//----------------------
142278332Semaste// destructor
143278332Semaste//----------------------
144278332Semaste
145278332SemasteCompactUnwindInfo::~CompactUnwindInfo()
146278332Semaste{
147278332Semaste}
148278332Semaste
149278332Semastebool
150278332SemasteCompactUnwindInfo::GetUnwindPlan (Target &target, Address addr, UnwindPlan& unwind_plan)
151278332Semaste{
152278332Semaste    if (!IsValid (target.GetProcessSP()))
153278332Semaste    {
154278332Semaste        return false;
155278332Semaste    }
156278332Semaste    FunctionInfo function_info;
157278332Semaste    if (GetCompactUnwindInfoForFunction (target, addr, function_info))
158278332Semaste    {
159278332Semaste        // shortcut return for functions that have no compact unwind
160278332Semaste        if (function_info.encoding == 0)
161278332Semaste            return false;
162278332Semaste
163278332Semaste        ArchSpec arch;
164278332Semaste        if (m_objfile.GetArchitecture (arch))
165278332Semaste        {
166278332Semaste
167278332Semaste            Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
168278332Semaste            if (log && log->GetVerbose())
169278332Semaste            {
170278332Semaste                StreamString strm;
171278332Semaste                addr.Dump (&strm, NULL, Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments, Address::DumpStyle::DumpStyleFileAddress, arch.GetAddressByteSize());
172278332Semaste                log->Printf ("Got compact unwind encoding 0x%x for function %s", function_info.encoding, strm.GetData());
173278332Semaste            }
174278332Semaste
175278332Semaste            if (function_info.valid_range_offset_start != 0 && function_info.valid_range_offset_end != 0)
176278332Semaste            {
177278332Semaste                SectionList *sl = m_objfile.GetSectionList ();
178278332Semaste                if (sl)
179278332Semaste                {
180278332Semaste                    addr_t func_range_start_file_addr =
181278332Semaste                              function_info.valid_range_offset_start + m_objfile.GetHeaderAddress().GetFileAddress();
182278332Semaste                    AddressRange func_range (func_range_start_file_addr,
183278332Semaste                                      function_info.valid_range_offset_end - function_info.valid_range_offset_start,
184278332Semaste                                      sl);
185278332Semaste                    unwind_plan.SetPlanValidAddressRange (func_range);
186278332Semaste                }
187278332Semaste            }
188278332Semaste
189278332Semaste            if (arch.GetTriple().getArch() == llvm::Triple::x86_64)
190278332Semaste            {
191278332Semaste                return CreateUnwindPlan_x86_64 (target, function_info, unwind_plan, addr);
192278332Semaste            }
193278332Semaste            if (arch.GetTriple().getArch() == llvm::Triple::x86)
194278332Semaste            {
195278332Semaste                return CreateUnwindPlan_i386 (target, function_info, unwind_plan, addr);
196278332Semaste            }
197278332Semaste        }
198278332Semaste    }
199278332Semaste    return false;
200278332Semaste}
201278332Semaste
202278332Semastebool
203278332SemasteCompactUnwindInfo::IsValid (const ProcessSP &process_sp)
204278332Semaste{
205278332Semaste    if (m_section_sp.get() == nullptr)
206278332Semaste        return false;
207278332Semaste
208278332Semaste    if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
209278332Semaste        return true;
210278332Semaste
211278332Semaste    ScanIndex (process_sp);
212278332Semaste
213278332Semaste    return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
214278332Semaste}
215278332Semaste
216278332Semastevoid
217278332SemasteCompactUnwindInfo::ScanIndex (const ProcessSP &process_sp)
218278332Semaste{
219278332Semaste    Mutex::Locker locker(m_mutex);
220278332Semaste    if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
221278332Semaste        return;
222278332Semaste
223278332Semaste    // We can't read the index for some reason.
224278332Semaste    if (m_indexes_computed == eLazyBoolNo)
225278332Semaste    {
226278332Semaste        return;
227278332Semaste    }
228278332Semaste
229278332Semaste    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
230278332Semaste    if (log)
231278332Semaste        m_objfile.GetModule()->LogMessage(log, "Reading compact unwind first-level indexes");
232278332Semaste
233278332Semaste    if (m_unwindinfo_data_computed == false)
234278332Semaste    {
235278332Semaste        if (m_section_sp->IsEncrypted())
236278332Semaste        {
237278332Semaste            // Can't get section contents of a protected/encrypted section until we have a live
238278332Semaste            // process and can read them out of memory.
239278332Semaste            if (process_sp.get() == nullptr)
240278332Semaste                return;
241278332Semaste            m_section_contents_if_encrypted.reset (new DataBufferHeap (m_section_sp->GetByteSize(), 0));
242278332Semaste            Error error;
243278332Semaste            if (process_sp->ReadMemory (
244278332Semaste                        m_section_sp->GetLoadBaseAddress (&process_sp->GetTarget()),
245278332Semaste                        m_section_contents_if_encrypted->GetBytes(),
246278332Semaste                        m_section_sp->GetByteSize(), error) == m_section_sp->GetByteSize() && error.Success())
247278332Semaste            {
248278332Semaste                m_unwindinfo_data.SetAddressByteSize (process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
249278332Semaste                m_unwindinfo_data.SetByteOrder (process_sp->GetTarget().GetArchitecture().GetByteOrder());
250278332Semaste                m_unwindinfo_data.SetData (m_section_contents_if_encrypted, 0);
251278332Semaste            }
252278332Semaste        }
253278332Semaste        else
254278332Semaste        {
255278332Semaste            m_objfile.ReadSectionData (m_section_sp.get(), m_unwindinfo_data);
256278332Semaste        }
257278332Semaste        if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
258278332Semaste            return;
259278332Semaste        m_unwindinfo_data_computed = true;
260278332Semaste    }
261278332Semaste
262278332Semaste    if (m_unwindinfo_data.GetByteSize() > 0)
263278332Semaste    {
264278332Semaste        offset_t offset = 0;
265278332Semaste
266278332Semaste                // struct unwind_info_section_header
267278332Semaste                // {
268278332Semaste                // uint32_t    version;            // UNWIND_SECTION_VERSION
269278332Semaste                // uint32_t    commonEncodingsArraySectionOffset;
270278332Semaste                // uint32_t    commonEncodingsArrayCount;
271278332Semaste                // uint32_t    personalityArraySectionOffset;
272278332Semaste                // uint32_t    personalityArrayCount;
273278332Semaste                // uint32_t    indexSectionOffset;
274278332Semaste                // uint32_t    indexCount;
275278332Semaste
276278332Semaste        m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);
277278332Semaste        m_unwind_header.common_encodings_array_offset = m_unwindinfo_data.GetU32(&offset);
278278332Semaste        m_unwind_header.common_encodings_array_count = m_unwindinfo_data.GetU32(&offset);
279278332Semaste        m_unwind_header.personality_array_offset = m_unwindinfo_data.GetU32(&offset);
280278332Semaste        m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);
281278332Semaste        uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);
282278332Semaste
283278332Semaste        uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
284278332Semaste
285278332Semaste        if (m_unwind_header.version != 1)
286278332Semaste        {
287278332Semaste            m_indexes_computed = eLazyBoolNo;
288278332Semaste        }
289278332Semaste
290278332Semaste        // Parse the basic information from the indexes
291278332Semaste        // We wait to scan the second level page info until it's needed
292278332Semaste
293278332Semaste            // struct unwind_info_section_header_index_entry
294278332Semaste            // {
295278332Semaste            //     uint32_t        functionOffset;
296278332Semaste            //     uint32_t        secondLevelPagesSectionOffset;
297278332Semaste            //     uint32_t        lsdaIndexArraySectionOffset;
298278332Semaste            // };
299278332Semaste
300278332Semaste        offset = indexSectionOffset;
301278332Semaste        for (uint32_t idx = 0; idx < indexCount; idx++)
302278332Semaste        {
303278332Semaste            uint32_t function_offset = m_unwindinfo_data.GetU32(&offset);      // functionOffset
304278332Semaste            uint32_t second_level_offset = m_unwindinfo_data.GetU32(&offset);  // secondLevelPagesSectionOffset
305278332Semaste            uint32_t lsda_offset = m_unwindinfo_data.GetU32(&offset);          // lsdaIndexArraySectionOffset
306278332Semaste
307278332Semaste            if (second_level_offset > m_section_sp->GetByteSize() || lsda_offset > m_section_sp->GetByteSize())
308278332Semaste            {
309278332Semaste                m_indexes_computed = eLazyBoolNo;
310278332Semaste            }
311278332Semaste
312278332Semaste            UnwindIndex this_index;
313278332Semaste            this_index.function_offset = function_offset;     //
314278332Semaste            this_index.second_level = second_level_offset;
315278332Semaste            this_index.lsda_array_start = lsda_offset;
316278332Semaste
317278332Semaste            if (m_indexes.size() > 0)
318278332Semaste            {
319278332Semaste                m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
320278332Semaste            }
321278332Semaste
322278332Semaste            if (second_level_offset == 0)
323278332Semaste            {
324278332Semaste                this_index.sentinal_entry = true;
325278332Semaste            }
326278332Semaste
327278332Semaste            m_indexes.push_back (this_index);
328278332Semaste        }
329278332Semaste        m_indexes_computed = eLazyBoolYes;
330278332Semaste    }
331278332Semaste    else
332278332Semaste    {
333278332Semaste        m_indexes_computed = eLazyBoolNo;
334278332Semaste    }
335278332Semaste}
336278332Semaste
337278332Semasteuint32_t
338278332SemasteCompactUnwindInfo::GetLSDAForFunctionOffset (uint32_t lsda_offset, uint32_t lsda_count, uint32_t function_offset)
339278332Semaste{
340278332Semaste        // struct unwind_info_section_header_lsda_index_entry
341278332Semaste        // {
342278332Semaste        //         uint32_t        functionOffset;
343278332Semaste        //         uint32_t        lsdaOffset;
344278332Semaste        // };
345278332Semaste
346278332Semaste    offset_t first_entry = lsda_offset;
347278332Semaste    uint32_t low = 0;
348278332Semaste    uint32_t high = lsda_count;
349278332Semaste    while (low < high)
350278332Semaste    {
351278332Semaste        uint32_t mid = (low + high) / 2;
352278332Semaste        offset_t offset = first_entry + (mid * 8);
353278332Semaste        uint32_t mid_func_offset = m_unwindinfo_data.GetU32(&offset);  // functionOffset
354278332Semaste        uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset);  // lsdaOffset
355278332Semaste        if (mid_func_offset == function_offset)
356278332Semaste        {
357278332Semaste            return mid_lsda_offset;
358278332Semaste        }
359278332Semaste        if (mid_func_offset < function_offset)
360278332Semaste        {
361278332Semaste            low = mid + 1;
362278332Semaste        }
363278332Semaste        else
364278332Semaste        {
365278332Semaste            high = mid;
366278332Semaste        }
367278332Semaste    }
368278332Semaste    return 0;
369278332Semaste}
370278332Semaste
371278332Semastelldb::offset_t
372278332SemasteCompactUnwindInfo::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)
373278332Semaste{
374278332Semaste    // typedef uint32_t compact_unwind_encoding_t;
375278332Semaste    // struct unwind_info_regular_second_level_entry
376278332Semaste    // {
377278332Semaste    //     uint32_t                    functionOffset;
378278332Semaste    //     compact_unwind_encoding_t    encoding;
379278332Semaste
380278332Semaste    offset_t first_entry = entry_page_offset;
381278332Semaste
382278332Semaste    uint32_t low = 0;
383278332Semaste    uint32_t high = entry_count;
384278332Semaste    uint32_t last = high - 1;
385278332Semaste    while (low < high)
386278332Semaste    {
387278332Semaste        uint32_t mid = (low + high) / 2;
388278332Semaste        offset_t offset = first_entry + (mid * 8);
389278332Semaste        uint32_t mid_func_offset = m_unwindinfo_data.GetU32(&offset);   // functionOffset
390278332Semaste        uint32_t next_func_offset = 0;
391278332Semaste        if (mid < last)
392278332Semaste        {
393278332Semaste            offset = first_entry + ((mid + 1) * 8);
394278332Semaste            next_func_offset = m_unwindinfo_data.GetU32(&offset);       // functionOffset
395278332Semaste        }
396278332Semaste        if (mid_func_offset <= function_offset)
397278332Semaste        {
398278332Semaste            if (mid == last || (next_func_offset > function_offset))
399278332Semaste            {
400278332Semaste                if (entry_func_start_offset)
401278332Semaste                    *entry_func_start_offset = mid_func_offset;
402278332Semaste                if (mid != last && entry_func_end_offset)
403278332Semaste                    *entry_func_end_offset = next_func_offset;
404278332Semaste                return first_entry + (mid * 8);
405278332Semaste            }
406278332Semaste            else
407278332Semaste            {
408278332Semaste                low = mid + 1;
409278332Semaste            }
410278332Semaste        }
411278332Semaste        else
412278332Semaste        {
413278332Semaste            high = mid;
414278332Semaste        }
415278332Semaste    }
416278332Semaste    return LLDB_INVALID_OFFSET;
417278332Semaste}
418278332Semaste
419278332Semasteuint32_t
420278332SemasteCompactUnwindInfo::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)
421278332Semaste{
422278332Semaste    offset_t first_entry = entry_page_offset;
423278332Semaste
424278332Semaste    uint32_t low = 0;
425278332Semaste    uint32_t high = entry_count;
426278332Semaste    uint32_t last = high - 1;
427278332Semaste    while (low < high)
428278332Semaste    {
429278332Semaste        uint32_t mid = (low + high) / 2;
430278332Semaste        offset_t offset = first_entry + (mid * 4);
431278332Semaste        uint32_t entry = m_unwindinfo_data.GetU32(&offset);   // entry
432278332Semaste        uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (entry);
433278332Semaste        mid_func_offset += function_offset_base;
434278332Semaste        uint32_t next_func_offset = 0;
435278332Semaste        if (mid < last)
436278332Semaste        {
437278332Semaste            offset = first_entry + ((mid + 1) * 4);
438278332Semaste            uint32_t next_entry = m_unwindinfo_data.GetU32(&offset);       // entry
439278332Semaste            next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (next_entry);
440278332Semaste            next_func_offset += function_offset_base;
441278332Semaste        }
442278332Semaste        if (mid_func_offset <= function_offset_to_find)
443278332Semaste        {
444278332Semaste            if (mid == last || (next_func_offset > function_offset_to_find))
445278332Semaste            {
446278332Semaste                if (entry_func_start_offset)
447278332Semaste                    *entry_func_start_offset = mid_func_offset;
448278332Semaste                if (mid != last && entry_func_end_offset)
449278332Semaste                    *entry_func_end_offset = next_func_offset;
450278332Semaste                return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX (entry);
451278332Semaste            }
452278332Semaste            else
453278332Semaste            {
454278332Semaste                low = mid + 1;
455278332Semaste            }
456278332Semaste        }
457278332Semaste        else
458278332Semaste        {
459278332Semaste            high = mid;
460278332Semaste        }
461278332Semaste    }
462278332Semaste
463278332Semaste    return UINT32_MAX;
464278332Semaste}
465278332Semaste
466278332Semastebool
467278332SemasteCompactUnwindInfo::GetCompactUnwindInfoForFunction (Target &target, Address address, FunctionInfo &unwind_info)
468278332Semaste{
469278332Semaste    unwind_info.encoding = 0;
470278332Semaste    unwind_info.lsda_address.Clear();
471278332Semaste    unwind_info.personality_ptr_address.Clear();
472278332Semaste
473278332Semaste    if (!IsValid (target.GetProcessSP()))
474278332Semaste        return false;
475278332Semaste
476278332Semaste    addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
477278332Semaste    SectionList *sl = m_objfile.GetSectionList ();
478278332Semaste    if (sl)
479278332Semaste    {
480278332Semaste        SectionSP text_sect = sl->FindSectionByType (eSectionTypeCode, true);
481278332Semaste        if (text_sect.get())
482278332Semaste        {
483278332Semaste           text_section_file_address = text_sect->GetFileAddress();
484278332Semaste        }
485278332Semaste    }
486278332Semaste    if (text_section_file_address == LLDB_INVALID_ADDRESS)
487278332Semaste        return false;
488278332Semaste
489278332Semaste    addr_t function_offset = address.GetFileAddress() - m_objfile.GetHeaderAddress().GetFileAddress();
490278332Semaste
491278332Semaste    UnwindIndex key;
492278332Semaste    key.function_offset = function_offset;
493278332Semaste
494278332Semaste    std::vector<UnwindIndex>::const_iterator it;
495278332Semaste    it = std::lower_bound (m_indexes.begin(), m_indexes.end(), key);
496278332Semaste    if (it == m_indexes.end())
497278332Semaste    {
498278332Semaste        return false;
499278332Semaste    }
500278332Semaste
501278332Semaste    if (it->function_offset != key.function_offset)
502278332Semaste    {
503278332Semaste        if (it != m_indexes.begin())
504278332Semaste            --it;
505278332Semaste    }
506278332Semaste
507278332Semaste    if (it->sentinal_entry == true)
508278332Semaste    {
509278332Semaste        return false;
510278332Semaste    }
511278332Semaste
512278332Semaste    auto next_it = it + 1;
513278332Semaste    if (next_it != m_indexes.begin())
514278332Semaste    {
515278332Semaste        // initialize the function offset end range to be the start of the
516278332Semaste        // next index offset.  If we find an entry which is at the end of
517278332Semaste        // the index table, this will establish the range end.
518278332Semaste        unwind_info.valid_range_offset_end = next_it->function_offset;
519278332Semaste    }
520278332Semaste
521278332Semaste    offset_t second_page_offset = it->second_level;
522278332Semaste    offset_t lsda_array_start = it->lsda_array_start;
523278332Semaste    offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
524278332Semaste
525278332Semaste    offset_t offset = second_page_offset;
526278332Semaste    uint32_t kind = m_unwindinfo_data.GetU32(&offset);  // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED
527278332Semaste
528278332Semaste    if (kind == UNWIND_SECOND_LEVEL_REGULAR)
529278332Semaste    {
530278332Semaste            // struct unwind_info_regular_second_level_page_header
531278332Semaste            // {
532278332Semaste            //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_REGULAR
533278332Semaste            //     uint16_t    entryPageOffset;
534278332Semaste            //     uint16_t    entryCount;
535278332Semaste
536278332Semaste            // typedef uint32_t compact_unwind_encoding_t;
537278332Semaste            // struct unwind_info_regular_second_level_entry
538278332Semaste            // {
539278332Semaste            //     uint32_t                    functionOffset;
540278332Semaste            //     compact_unwind_encoding_t    encoding;
541278332Semaste
542278332Semaste        uint16_t entry_page_offset = m_unwindinfo_data.GetU16(&offset); // entryPageOffset
543278332Semaste        uint16_t entry_count = m_unwindinfo_data.GetU16(&offset);       // entryCount
544278332Semaste
545278332Semaste        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);
546278332Semaste        if (entry_offset == LLDB_INVALID_OFFSET)
547278332Semaste        {
548278332Semaste            return false;
549278332Semaste        }
550278332Semaste        entry_offset += 4;                                              // skip over functionOffset
551278332Semaste        unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding
552278332Semaste        if (unwind_info.encoding & UNWIND_HAS_LSDA)
553278332Semaste        {
554278332Semaste            SectionList *sl = m_objfile.GetSectionList ();
555278332Semaste            if (sl)
556278332Semaste            {
557278332Semaste                uint32_t lsda_offset = GetLSDAForFunctionOffset (lsda_array_start, lsda_array_count, function_offset);
558278332Semaste                addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
559278332Semaste                unwind_info.lsda_address.ResolveAddressUsingFileSections (objfile_header_file_address + lsda_offset, sl);
560278332Semaste            }
561278332Semaste        }
562278332Semaste        if (unwind_info.encoding & UNWIND_PERSONALITY_MASK)
563278332Semaste        {
564278332Semaste            uint32_t personality_index = EXTRACT_BITS (unwind_info.encoding, UNWIND_PERSONALITY_MASK);
565278332Semaste
566278332Semaste            if (personality_index > 0)
567278332Semaste            {
568278332Semaste                personality_index--;
569278332Semaste                if (personality_index < m_unwind_header.personality_array_count)
570278332Semaste                {
571278332Semaste                    offset_t offset = m_unwind_header.personality_array_offset;
572278332Semaste                    offset += 4 * personality_index;
573278332Semaste                    SectionList *sl = m_objfile.GetSectionList ();
574278332Semaste                    if (sl)
575278332Semaste                    {
576278332Semaste                        uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
577278332Semaste                        addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
578278332Semaste                        unwind_info.personality_ptr_address.ResolveAddressUsingFileSections (objfile_header_file_address + personality_offset, sl);
579278332Semaste                    }
580278332Semaste                }
581278332Semaste            }
582278332Semaste        }
583278332Semaste        return true;
584278332Semaste    }
585278332Semaste    else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED)
586278332Semaste    {
587278332Semaste            // struct unwind_info_compressed_second_level_page_header
588278332Semaste            // {
589278332Semaste            //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_COMPRESSED
590278332Semaste            //     uint16_t    entryPageOffset;         // offset from this 2nd lvl page idx to array of entries
591278332Semaste            //                                          // (an entry has a function offset and index into the encodings)
592278332Semaste            //                                          // NB function offset from the entry in the compressed page
593278332Semaste            //                                          // must be added to the index's functionOffset value.
594278332Semaste            //     uint16_t    entryCount;
595278332Semaste            //     uint16_t    encodingsPageOffset;     // offset from this 2nd lvl page idx to array of encodings
596278332Semaste            //     uint16_t    encodingsCount;
597278332Semaste
598278332Semaste        uint16_t entry_page_offset = m_unwindinfo_data.GetU16(&offset);     // entryPageOffset
599278332Semaste        uint16_t entry_count = m_unwindinfo_data.GetU16(&offset);           // entryCount
600278332Semaste        uint16_t encodings_page_offset = m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
601278332Semaste        uint16_t encodings_count = m_unwindinfo_data.GetU16(&offset);       // encodingsCount
602278332Semaste
603278332Semaste        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);
604278332Semaste        if (encoding_index == UINT32_MAX || encoding_index >= encodings_count + m_unwind_header.common_encodings_array_count)
605278332Semaste        {
606278332Semaste            return false;
607278332Semaste        }
608278332Semaste        uint32_t encoding = 0;
609278332Semaste        if (encoding_index < m_unwind_header.common_encodings_array_count)
610278332Semaste        {
611278332Semaste            offset = m_unwind_header.common_encodings_array_offset + (encoding_index * sizeof (uint32_t));
612278332Semaste            encoding = m_unwindinfo_data.GetU32(&offset);   // encoding entry from the commonEncodingsArray
613278332Semaste        }
614278332Semaste        else
615278332Semaste        {
616278332Semaste            uint32_t page_specific_entry_index = encoding_index - m_unwind_header.common_encodings_array_count;
617278332Semaste            offset = second_page_offset + encodings_page_offset + (page_specific_entry_index * sizeof (uint32_t));
618278332Semaste            encoding = m_unwindinfo_data.GetU32(&offset);   // encoding entry from the page-specific encoding array
619278332Semaste        }
620278332Semaste        if (encoding == 0)
621278332Semaste            return false;
622278332Semaste
623278332Semaste        unwind_info.encoding = encoding;
624278332Semaste        if (unwind_info.encoding & UNWIND_HAS_LSDA)
625278332Semaste        {
626278332Semaste            SectionList *sl = m_objfile.GetSectionList ();
627278332Semaste            if (sl)
628278332Semaste            {
629278332Semaste                uint32_t lsda_offset = GetLSDAForFunctionOffset (lsda_array_start, lsda_array_count, function_offset);
630278332Semaste                addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
631278332Semaste                unwind_info.lsda_address.ResolveAddressUsingFileSections (objfile_header_file_address + lsda_offset, sl);
632278332Semaste            }
633278332Semaste        }
634278332Semaste        if (unwind_info.encoding & UNWIND_PERSONALITY_MASK)
635278332Semaste        {
636278332Semaste            uint32_t personality_index = EXTRACT_BITS (unwind_info.encoding, UNWIND_PERSONALITY_MASK);
637278332Semaste
638278332Semaste            if (personality_index > 0)
639278332Semaste            {
640278332Semaste                personality_index--;
641278332Semaste                if (personality_index < m_unwind_header.personality_array_count)
642278332Semaste                {
643278332Semaste                    offset_t offset = m_unwind_header.personality_array_offset;
644278332Semaste                    offset += 4 * personality_index;
645278332Semaste                    SectionList *sl = m_objfile.GetSectionList ();
646278332Semaste                    if (sl)
647278332Semaste                    {
648278332Semaste                        uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
649278332Semaste                        addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress();
650278332Semaste                        unwind_info.personality_ptr_address.ResolveAddressUsingFileSections (objfile_header_file_address + personality_offset, sl);
651278332Semaste                    }
652278332Semaste                }
653278332Semaste            }
654278332Semaste        }
655278332Semaste        return true;
656278332Semaste    }
657278332Semaste    return false;
658278332Semaste}
659278332Semaste
660278332Semasteenum x86_64_eh_regnum {
661278332Semaste    rax = 0,
662278332Semaste    rdx = 1,
663278332Semaste    rcx = 2,
664278332Semaste    rbx = 3,
665278332Semaste    rsi = 4,
666278332Semaste    rdi = 5,
667278332Semaste    rbp = 6,
668278332Semaste    rsp = 7,
669278332Semaste    r8 = 8,
670278332Semaste    r9 = 9,
671278332Semaste    r10 = 10,
672278332Semaste    r11 = 11,
673278332Semaste    r12 = 12,
674278332Semaste    r13 = 13,
675278332Semaste    r14 = 14,
676278332Semaste    r15 = 15,
677278332Semaste    rip = 16   // this is officially the Return Address register number, but close enough
678278332Semaste};
679278332Semaste
680278332Semaste// Convert the compact_unwind_info.h register numbering scheme
681278332Semaste// to eRegisterKindGCC (eh_frame) register numbering scheme.
682278332Semasteuint32_t
683278332Semastetranslate_to_eh_frame_regnum_x86_64 (uint32_t unwind_regno)
684278332Semaste{
685278332Semaste    switch (unwind_regno)
686278332Semaste    {
687278332Semaste        case UNWIND_X86_64_REG_RBX:
688278332Semaste            return x86_64_eh_regnum::rbx;
689278332Semaste        case UNWIND_X86_64_REG_R12:
690278332Semaste            return x86_64_eh_regnum::r12;
691278332Semaste        case UNWIND_X86_64_REG_R13:
692278332Semaste            return x86_64_eh_regnum::r13;
693278332Semaste        case UNWIND_X86_64_REG_R14:
694278332Semaste            return x86_64_eh_regnum::r14;
695278332Semaste        case UNWIND_X86_64_REG_R15:
696278332Semaste            return x86_64_eh_regnum::r15;
697278332Semaste        case UNWIND_X86_64_REG_RBP:
698278332Semaste            return x86_64_eh_regnum::rbp;
699278332Semaste        default:
700278332Semaste            return LLDB_INVALID_REGNUM;
701278332Semaste    }
702278332Semaste}
703278332Semaste
704278332Semastebool
705278332SemasteCompactUnwindInfo::CreateUnwindPlan_x86_64 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start)
706278332Semaste{
707278332Semaste    unwind_plan.SetSourceName ("compact unwind info");
708278332Semaste    unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);
709278332Semaste    unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
710278332Semaste    unwind_plan.SetRegisterKind (eRegisterKindGCC);
711278332Semaste
712278332Semaste    unwind_plan.SetLSDAAddress (function_info.lsda_address);
713278332Semaste    unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address);
714278332Semaste
715278332Semaste    UnwindPlan::RowSP row (new UnwindPlan::Row);
716278332Semaste
717278332Semaste    const int wordsize = 8;
718278332Semaste    int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
719278332Semaste    switch (mode)
720278332Semaste    {
721278332Semaste        case UNWIND_X86_64_MODE_RBP_FRAME:
722278332Semaste        {
723278332Semaste            row->SetCFARegister (translate_to_eh_frame_regnum_x86_64 (UNWIND_X86_64_REG_RBP));
724278332Semaste            row->SetCFAOffset (2 * wordsize);
725278332Semaste            row->SetOffset (0);
726278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rbp, wordsize * -2, true);
727278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true);
728278332Semaste            row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true);
729278332Semaste
730278332Semaste            uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
731278332Semaste
732278332Semaste            uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
733278332Semaste
734278332Semaste            saved_registers_offset += 2;
735278332Semaste
736278332Semaste            for (int i = 0; i < 5; i++)
737278332Semaste            {
738278332Semaste                uint32_t regnum = saved_registers_locations & 0x7;
739278332Semaste                switch (regnum)
740278332Semaste                {
741278332Semaste                    case UNWIND_X86_64_REG_NONE:
742278332Semaste                        break;
743278332Semaste                    case UNWIND_X86_64_REG_RBX:
744278332Semaste                    case UNWIND_X86_64_REG_R12:
745278332Semaste                    case UNWIND_X86_64_REG_R13:
746278332Semaste                    case UNWIND_X86_64_REG_R14:
747278332Semaste                    case UNWIND_X86_64_REG_R15:
748278332Semaste                        row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (regnum), wordsize * -saved_registers_offset, true);
749278332Semaste                        break;
750278332Semaste                }
751278332Semaste                saved_registers_offset--;
752278332Semaste                saved_registers_locations >>= 3;
753278332Semaste            }
754278332Semaste            unwind_plan.AppendRow (row);
755278332Semaste            return true;
756278332Semaste        }
757278332Semaste        break;
758278332Semaste
759278332Semaste        case UNWIND_X86_64_MODE_STACK_IND:
760278332Semaste        {
761278332Semaste            // The clang in Xcode 6 is emitting incorrect compact unwind encodings for this
762278332Semaste            // style of unwind.  It was fixed in llvm r217020.
763278332Semaste            return false;
764278332Semaste        }
765278332Semaste        break;
766278332Semaste
767278332Semaste        case UNWIND_X86_64_MODE_STACK_IMMD:
768278332Semaste        {
769278332Semaste            uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
770278332Semaste            uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
771278332Semaste            uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
772278332Semaste
773278332Semaste            if (mode == UNWIND_X86_64_MODE_STACK_IND && function_info.valid_range_offset_start != 0)
774278332Semaste            {
775278332Semaste                uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
776278332Semaste
777278332Semaste                // offset into the function instructions; 0 == beginning of first instruction
778278332Semaste                uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
779278332Semaste
780278332Semaste                SectionList *sl = m_objfile.GetSectionList ();
781278332Semaste                if (sl)
782278332Semaste                {
783278332Semaste                    ProcessSP process_sp = target.GetProcessSP();
784278332Semaste                    if (process_sp)
785278332Semaste                    {
786278332Semaste                        Address subl_payload_addr (function_info.valid_range_offset_start, sl);
787278332Semaste                        subl_payload_addr.Slide (offset_to_subl_insn);
788278332Semaste                        Error error;
789278332Semaste                        uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target),
790278332Semaste                                4, 0, error);
791278332Semaste                        if (large_stack_size != 0 && error.Success ())
792278332Semaste                        {
793278332Semaste                            // Got the large stack frame size correctly - use it
794278332Semaste                            stack_size = large_stack_size + (stack_adjust * wordsize);
795278332Semaste                        }
796278332Semaste                        else
797278332Semaste                        {
798278332Semaste                            return false;
799278332Semaste                        }
800278332Semaste                    }
801278332Semaste                    else
802278332Semaste                    {
803278332Semaste                        return false;
804278332Semaste                    }
805278332Semaste                }
806278332Semaste                else
807278332Semaste                {
808278332Semaste                    return false;
809278332Semaste                }
810278332Semaste            }
811278332Semaste
812278332Semaste            row->SetCFARegister (x86_64_eh_regnum::rsp);
813278332Semaste            row->SetCFAOffset (stack_size * wordsize);
814278332Semaste            row->SetOffset (0);
815278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true);
816278332Semaste            row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true);
817278332Semaste
818278332Semaste            if (register_count > 0)
819278332Semaste            {
820278332Semaste
821278332Semaste                // We need to include (up to) 6 registers in 10 bits.
822278332Semaste                // That would be 18 bits if we just used 3 bits per reg to indicate
823278332Semaste                // the order they're saved on the stack.
824278332Semaste                //
825278332Semaste                // This is done with Lehmer code permutation, e.g. see
826278332Semaste                // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
827278332Semaste                int permunreg[6];
828278332Semaste
829278332Semaste                // This decodes the variable-base number in the 10 bits
830278332Semaste                // and gives us the Lehmer code sequence which can then
831278332Semaste                // be decoded.
832278332Semaste
833278332Semaste                switch (register_count)
834278332Semaste                {
835278332Semaste                    case 6:
836278332Semaste                        permunreg[0] = permutation/120;    // 120 == 5!
837278332Semaste                        permutation -= (permunreg[0]*120);
838278332Semaste                        permunreg[1] = permutation/24;     // 24 == 4!
839278332Semaste                        permutation -= (permunreg[1]*24);
840278332Semaste                        permunreg[2] = permutation/6;      // 6 == 3!
841278332Semaste                        permutation -= (permunreg[2]*6);
842278332Semaste                        permunreg[3] = permutation/2;      // 2 == 2!
843278332Semaste                        permutation -= (permunreg[3]*2);
844278332Semaste                        permunreg[4] = permutation;        // 1 == 1!
845278332Semaste                        permunreg[5] = 0;
846278332Semaste                        break;
847278332Semaste                    case 5:
848278332Semaste                        permunreg[0] = permutation/120;
849278332Semaste                        permutation -= (permunreg[0]*120);
850278332Semaste                        permunreg[1] = permutation/24;
851278332Semaste                        permutation -= (permunreg[1]*24);
852278332Semaste                        permunreg[2] = permutation/6;
853278332Semaste                        permutation -= (permunreg[2]*6);
854278332Semaste                        permunreg[3] = permutation/2;
855278332Semaste                        permutation -= (permunreg[3]*2);
856278332Semaste                        permunreg[4] = permutation;
857278332Semaste                        break;
858278332Semaste                    case 4:
859278332Semaste                        permunreg[0] = permutation/60;
860278332Semaste                        permutation -= (permunreg[0]*60);
861278332Semaste                        permunreg[1] = permutation/12;
862278332Semaste                        permutation -= (permunreg[1]*12);
863278332Semaste                        permunreg[2] = permutation/3;
864278332Semaste                        permutation -= (permunreg[2]*3);
865278332Semaste                        permunreg[3] = permutation;
866278332Semaste                        break;
867278332Semaste                    case 3:
868278332Semaste                        permunreg[0] = permutation/20;
869278332Semaste                        permutation -= (permunreg[0]*20);
870278332Semaste                        permunreg[1] = permutation/4;
871278332Semaste                        permutation -= (permunreg[1]*4);
872278332Semaste                        permunreg[2] = permutation;
873278332Semaste                        break;
874278332Semaste                    case 2:
875278332Semaste                        permunreg[0] = permutation/5;
876278332Semaste                        permutation -= (permunreg[0]*5);
877278332Semaste                        permunreg[1] = permutation;
878278332Semaste                        break;
879278332Semaste                    case 1:
880278332Semaste                        permunreg[0] = permutation;
881278332Semaste                        break;
882278332Semaste                }
883278332Semaste
884278332Semaste                // Decode the Lehmer code for this permutation of
885278332Semaste                // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
886278332Semaste
887278332Semaste                int registers[6];
888278332Semaste                bool used[7] = { false, false, false, false, false, false, false };
889278332Semaste                for (uint32_t i = 0; i < register_count; i++)
890278332Semaste                {
891278332Semaste                    int renum = 0;
892278332Semaste                    for (int j = 1; j < 7; j++)
893278332Semaste                    {
894278332Semaste                        if (used[j] == false)
895278332Semaste                        {
896278332Semaste                            if (renum == permunreg[i])
897278332Semaste                            {
898278332Semaste                                registers[i] = j;
899278332Semaste                                used[j] = true;
900278332Semaste                                break;
901278332Semaste                            }
902278332Semaste                            renum++;
903278332Semaste                        }
904278332Semaste                    }
905278332Semaste                }
906278332Semaste
907278332Semaste                uint32_t saved_registers_offset = 1;
908278332Semaste                saved_registers_offset++;
909278332Semaste
910278332Semaste                for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
911278332Semaste                {
912278332Semaste                    switch (registers[i])
913278332Semaste                    {
914278332Semaste                        case UNWIND_X86_64_REG_NONE:
915278332Semaste                            break;
916278332Semaste                        case UNWIND_X86_64_REG_RBX:
917278332Semaste                        case UNWIND_X86_64_REG_R12:
918278332Semaste                        case UNWIND_X86_64_REG_R13:
919278332Semaste                        case UNWIND_X86_64_REG_R14:
920278332Semaste                        case UNWIND_X86_64_REG_R15:
921278332Semaste                        case UNWIND_X86_64_REG_RBP:
922278332Semaste                             row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (registers[i]), wordsize * -saved_registers_offset, true);
923278332Semaste                        break;
924278332Semaste                    }
925278332Semaste                    saved_registers_offset++;
926278332Semaste                }
927278332Semaste            }
928278332Semaste            unwind_plan.AppendRow (row);
929278332Semaste            return true;
930278332Semaste        }
931278332Semaste        break;
932278332Semaste
933278332Semaste        case UNWIND_X86_64_MODE_DWARF:
934278332Semaste        {
935278332Semaste            return false;
936278332Semaste        }
937278332Semaste        break;
938278332Semaste
939278332Semaste        case 0:
940278332Semaste        {
941278332Semaste            return false;
942278332Semaste        }
943278332Semaste        break;
944278332Semaste    }
945278332Semaste    return false;
946278332Semaste}
947278332Semaste
948278332Semasteenum i386_eh_regnum {
949278332Semaste    eax = 0,
950278332Semaste    ecx = 1,
951278332Semaste    edx = 2,
952278332Semaste    ebx = 3,
953278332Semaste    ebp = 4,
954278332Semaste    esp = 5,
955278332Semaste    esi = 6,
956278332Semaste    edi = 7,
957278332Semaste    eip = 8    // this is officially the Return Address register number, but close enough
958278332Semaste};
959278332Semaste
960278332Semaste// Convert the compact_unwind_info.h register numbering scheme
961278332Semaste// to eRegisterKindGCC (eh_frame) register numbering scheme.
962278332Semasteuint32_t
963278332Semastetranslate_to_eh_frame_regnum_i386 (uint32_t unwind_regno)
964278332Semaste{
965278332Semaste    switch (unwind_regno)
966278332Semaste    {
967278332Semaste        case UNWIND_X86_REG_EBX:
968278332Semaste            return i386_eh_regnum::ebx;
969278332Semaste        case UNWIND_X86_REG_ECX:
970278332Semaste            return i386_eh_regnum::ecx;
971278332Semaste        case UNWIND_X86_REG_EDX:
972278332Semaste            return i386_eh_regnum::edx;
973278332Semaste        case UNWIND_X86_REG_EDI:
974278332Semaste            return i386_eh_regnum::edi;
975278332Semaste        case UNWIND_X86_REG_ESI:
976278332Semaste            return i386_eh_regnum::esi;
977278332Semaste        case UNWIND_X86_REG_EBP:
978278332Semaste            return i386_eh_regnum::ebp;
979278332Semaste        default:
980278332Semaste            return LLDB_INVALID_REGNUM;
981278332Semaste    }
982278332Semaste}
983278332Semaste
984278332Semaste
985278332Semastebool
986278332SemasteCompactUnwindInfo::CreateUnwindPlan_i386 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start)
987278332Semaste{
988278332Semaste    unwind_plan.SetSourceName ("compact unwind info");
989278332Semaste    unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);
990278332Semaste    unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
991278332Semaste    unwind_plan.SetRegisterKind (eRegisterKindGCC);
992278332Semaste
993278332Semaste    unwind_plan.SetLSDAAddress (function_info.lsda_address);
994278332Semaste    unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address);
995278332Semaste
996278332Semaste    UnwindPlan::RowSP row (new UnwindPlan::Row);
997278332Semaste
998278332Semaste    const int wordsize = 4;
999278332Semaste    int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
1000278332Semaste    switch (mode)
1001278332Semaste    {
1002278332Semaste        case UNWIND_X86_MODE_EBP_FRAME:
1003278332Semaste        {
1004278332Semaste            row->SetCFARegister (translate_to_eh_frame_regnum_i386 (UNWIND_X86_REG_EBP));
1005278332Semaste            row->SetCFAOffset (2 * wordsize);
1006278332Semaste            row->SetOffset (0);
1007278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::ebp, wordsize * -2, true);
1008278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true);
1009278332Semaste            row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true);
1010278332Semaste
1011278332Semaste            uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
1012278332Semaste
1013278332Semaste            uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
1014278332Semaste
1015278332Semaste            saved_registers_offset += 2;
1016278332Semaste
1017278332Semaste            for (int i = 0; i < 5; i++)
1018278332Semaste            {
1019278332Semaste                uint32_t regnum = saved_registers_locations & 0x7;
1020278332Semaste                switch (regnum)
1021278332Semaste                {
1022278332Semaste                    case UNWIND_X86_REG_NONE:
1023278332Semaste                        break;
1024278332Semaste                    case UNWIND_X86_REG_EBX:
1025278332Semaste                    case UNWIND_X86_REG_ECX:
1026278332Semaste                    case UNWIND_X86_REG_EDX:
1027278332Semaste                    case UNWIND_X86_REG_EDI:
1028278332Semaste                    case UNWIND_X86_REG_ESI:
1029278332Semaste                        row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (regnum), wordsize * -saved_registers_offset, true);
1030278332Semaste                        break;
1031278332Semaste                }
1032278332Semaste                saved_registers_offset--;
1033278332Semaste                saved_registers_locations >>= 3;
1034278332Semaste            }
1035278332Semaste            unwind_plan.AppendRow (row);
1036278332Semaste            return true;
1037278332Semaste        }
1038278332Semaste        break;
1039278332Semaste
1040278332Semaste        case UNWIND_X86_MODE_STACK_IND:
1041278332Semaste        case UNWIND_X86_MODE_STACK_IMMD:
1042278332Semaste        {
1043278332Semaste            uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1044278332Semaste            uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
1045278332Semaste            uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
1046278332Semaste
1047278332Semaste            if (mode == UNWIND_X86_MODE_STACK_IND && function_info.valid_range_offset_start != 0)
1048278332Semaste            {
1049278332Semaste                uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
1050278332Semaste
1051278332Semaste                // offset into the function instructions; 0 == beginning of first instruction
1052278332Semaste                uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1053278332Semaste
1054278332Semaste                SectionList *sl = m_objfile.GetSectionList ();
1055278332Semaste                if (sl)
1056278332Semaste                {
1057278332Semaste                    ProcessSP process_sp = target.GetProcessSP();
1058278332Semaste                    if (process_sp)
1059278332Semaste                    {
1060278332Semaste                        Address subl_payload_addr (function_info.valid_range_offset_start, sl);
1061278332Semaste                        subl_payload_addr.Slide (offset_to_subl_insn);
1062278332Semaste                        Error error;
1063278332Semaste                        uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target),
1064278332Semaste                                4, 0, error);
1065278332Semaste                        if (large_stack_size != 0 && error.Success ())
1066278332Semaste                        {
1067278332Semaste                            // Got the large stack frame size correctly - use it
1068278332Semaste                            stack_size = large_stack_size + (stack_adjust * wordsize);
1069278332Semaste                        }
1070278332Semaste                        else
1071278332Semaste                        {
1072278332Semaste                            return false;
1073278332Semaste                        }
1074278332Semaste                    }
1075278332Semaste                    else
1076278332Semaste                    {
1077278332Semaste                        return false;
1078278332Semaste                    }
1079278332Semaste                }
1080278332Semaste                else
1081278332Semaste                {
1082278332Semaste                    return false;
1083278332Semaste                }
1084278332Semaste            }
1085278332Semaste
1086278332Semaste            row->SetCFARegister (i386_eh_regnum::esp);
1087278332Semaste            row->SetCFAOffset (stack_size * wordsize);
1088278332Semaste            row->SetOffset (0);
1089278332Semaste            row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true);
1090278332Semaste            row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true);
1091278332Semaste
1092278332Semaste            if (register_count > 0)
1093278332Semaste            {
1094278332Semaste
1095278332Semaste                // We need to include (up to) 6 registers in 10 bits.
1096278332Semaste                // That would be 18 bits if we just used 3 bits per reg to indicate
1097278332Semaste                // the order they're saved on the stack.
1098278332Semaste                //
1099278332Semaste                // This is done with Lehmer code permutation, e.g. see
1100278332Semaste                // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
1101278332Semaste                int permunreg[6];
1102278332Semaste
1103278332Semaste                // This decodes the variable-base number in the 10 bits
1104278332Semaste                // and gives us the Lehmer code sequence which can then
1105278332Semaste                // be decoded.
1106278332Semaste
1107278332Semaste                switch (register_count)
1108278332Semaste                {
1109278332Semaste                    case 6:
1110278332Semaste                        permunreg[0] = permutation/120;    // 120 == 5!
1111278332Semaste                        permutation -= (permunreg[0]*120);
1112278332Semaste                        permunreg[1] = permutation/24;     // 24 == 4!
1113278332Semaste                        permutation -= (permunreg[1]*24);
1114278332Semaste                        permunreg[2] = permutation/6;      // 6 == 3!
1115278332Semaste                        permutation -= (permunreg[2]*6);
1116278332Semaste                        permunreg[3] = permutation/2;      // 2 == 2!
1117278332Semaste                        permutation -= (permunreg[3]*2);
1118278332Semaste                        permunreg[4] = permutation;        // 1 == 1!
1119278332Semaste                        permunreg[5] = 0;
1120278332Semaste                        break;
1121278332Semaste                    case 5:
1122278332Semaste                        permunreg[0] = permutation/120;
1123278332Semaste                        permutation -= (permunreg[0]*120);
1124278332Semaste                        permunreg[1] = permutation/24;
1125278332Semaste                        permutation -= (permunreg[1]*24);
1126278332Semaste                        permunreg[2] = permutation/6;
1127278332Semaste                        permutation -= (permunreg[2]*6);
1128278332Semaste                        permunreg[3] = permutation/2;
1129278332Semaste                        permutation -= (permunreg[3]*2);
1130278332Semaste                        permunreg[4] = permutation;
1131278332Semaste                        break;
1132278332Semaste                    case 4:
1133278332Semaste                        permunreg[0] = permutation/60;
1134278332Semaste                        permutation -= (permunreg[0]*60);
1135278332Semaste                        permunreg[1] = permutation/12;
1136278332Semaste                        permutation -= (permunreg[1]*12);
1137278332Semaste                        permunreg[2] = permutation/3;
1138278332Semaste                        permutation -= (permunreg[2]*3);
1139278332Semaste                        permunreg[3] = permutation;
1140278332Semaste                        break;
1141278332Semaste                    case 3:
1142278332Semaste                        permunreg[0] = permutation/20;
1143278332Semaste                        permutation -= (permunreg[0]*20);
1144278332Semaste                        permunreg[1] = permutation/4;
1145278332Semaste                        permutation -= (permunreg[1]*4);
1146278332Semaste                        permunreg[2] = permutation;
1147278332Semaste                        break;
1148278332Semaste                    case 2:
1149278332Semaste                        permunreg[0] = permutation/5;
1150278332Semaste                        permutation -= (permunreg[0]*5);
1151278332Semaste                        permunreg[1] = permutation;
1152278332Semaste                        break;
1153278332Semaste                    case 1:
1154278332Semaste                        permunreg[0] = permutation;
1155278332Semaste                        break;
1156278332Semaste                }
1157278332Semaste
1158278332Semaste                // Decode the Lehmer code for this permutation of
1159278332Semaste                // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
1160278332Semaste
1161278332Semaste                int registers[6];
1162278332Semaste                bool used[7] = { false, false, false, false, false, false, false };
1163278332Semaste                for (uint32_t i = 0; i < register_count; i++)
1164278332Semaste                {
1165278332Semaste                    int renum = 0;
1166278332Semaste                    for (int j = 1; j < 7; j++)
1167278332Semaste                    {
1168278332Semaste                        if (used[j] == false)
1169278332Semaste                        {
1170278332Semaste                            if (renum == permunreg[i])
1171278332Semaste                            {
1172278332Semaste                                registers[i] = j;
1173278332Semaste                                used[j] = true;
1174278332Semaste                                break;
1175278332Semaste                            }
1176278332Semaste                            renum++;
1177278332Semaste                        }
1178278332Semaste                    }
1179278332Semaste                }
1180278332Semaste
1181278332Semaste                uint32_t saved_registers_offset = 1;
1182278332Semaste                saved_registers_offset++;
1183278332Semaste
1184278332Semaste                for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
1185278332Semaste                {
1186278332Semaste                    switch (registers[i])
1187278332Semaste                    {
1188278332Semaste                        case UNWIND_X86_REG_NONE:
1189278332Semaste                            break;
1190278332Semaste                        case UNWIND_X86_REG_EBX:
1191278332Semaste                        case UNWIND_X86_REG_ECX:
1192278332Semaste                        case UNWIND_X86_REG_EDX:
1193278332Semaste                        case UNWIND_X86_REG_EDI:
1194278332Semaste                        case UNWIND_X86_REG_ESI:
1195278332Semaste                        case UNWIND_X86_REG_EBP:
1196278332Semaste                             row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (registers[i]), wordsize * -saved_registers_offset, true);
1197278332Semaste                        break;
1198278332Semaste                    }
1199278332Semaste                    saved_registers_offset++;
1200278332Semaste                }
1201278332Semaste            }
1202278332Semaste
1203278332Semaste            unwind_plan.AppendRow (row);
1204278332Semaste            return true;
1205278332Semaste        }
1206278332Semaste        break;
1207278332Semaste
1208278332Semaste        case UNWIND_X86_MODE_DWARF:
1209278332Semaste        {
1210278332Semaste            return false;
1211278332Semaste        }
1212278332Semaste        break;
1213278332Semaste    }
1214278332Semaste    return false;
1215278332Semaste}
1216