aboutsummaryrefslogtreecommitdiff
path: root/include/lldb/Symbol/DWARFCallFrameInfo.h
blob: c221a36bd6c893b414cb81dcb3f5e7f94bfa05e9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//===-- DWARFCallFrameInfo.h ------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_DWARFCallFrameInfo_h_
#define liblldb_DWARFCallFrameInfo_h_

#include <map>
#include <mutex>

#include "lldb/Core/AddressRange.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Flags.h"
#include "lldb/Core/RangeMap.h"
#include "lldb/Core/VMRange.h"
#include "lldb/Core/dwarf.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/lldb-private.h"

namespace lldb_private {

// DWARFCallFrameInfo is a class which can read eh_frame and DWARF
// Call Frame Information FDEs.  It stores little information internally.
// Only two APIs are exported - one to find the high/low pc values
// of a function given a text address via the information in the
// eh_frame / debug_frame, and one to generate an UnwindPlan based
// on the FDE in the eh_frame / debug_frame section.

class DWARFCallFrameInfo {
public:
  DWARFCallFrameInfo(ObjectFile &objfile, lldb::SectionSP &section,
                     lldb::RegisterKind reg_kind, bool is_eh_frame);

  ~DWARFCallFrameInfo();

  // Locate an AddressRange that includes the provided Address in this
  // object's eh_frame/debug_info
  // Returns true if a range is found to cover that address.
  bool GetAddressRange(Address addr, AddressRange &range);

  // Return an UnwindPlan based on the call frame information encoded
  // in the FDE of this DWARFCallFrameInfo section.
  bool GetUnwindPlan(Address addr, UnwindPlan &unwind_plan);

  typedef RangeVector<lldb::addr_t, uint32_t> FunctionAddressAndSizeVector;

  //------------------------------------------------------------------
  // Build a vector of file address and size for all functions in this Module
  // based on the eh_frame FDE entries.
  //
  // The eh_frame information can be a useful source of file address and size of
  // the functions in a Module.  Often a binary's non-exported symbols are
  // stripped
  // before shipping so lldb won't know the start addr / size of many functions
  // in the Module.  But the eh_frame can help to give the addresses of these
  // stripped symbols, at least.
  //
  // @param[out] function_info
  //      A vector provided by the caller is filled out.  May be empty if no
  //      FDEs/no eh_frame
  //      is present in this Module.

  void
  GetFunctionAddressAndSizeVector(FunctionAddressAndSizeVector &function_info);

  void ForEachFDEEntries(
      const std::function<bool(lldb::addr_t, uint32_t, dw_offset_t)> &callback);

private:
  enum { CFI_AUG_MAX_SIZE = 8, CFI_HEADER_SIZE = 8 };

  struct CIE {
    dw_offset_t cie_offset;
    uint8_t version;
    char augmentation[CFI_AUG_MAX_SIZE]; // This is typically empty or very
                                         // short.
    uint32_t code_align;
    int32_t data_align;
    uint32_t return_addr_reg_num;
    dw_offset_t inst_offset; // offset of CIE instructions in mCFIData
    uint32_t inst_length;    // length of CIE instructions in mCFIData
    uint8_t ptr_encoding;
    uint8_t lsda_addr_encoding;   // The encoding of the LSDA address in the FDE
                                  // augmentation data
    lldb::addr_t personality_loc; // (file) address of the pointer to the
                                  // personality routine
    lldb_private::UnwindPlan::Row initial_row;

    CIE(dw_offset_t offset)
        : cie_offset(offset), version(-1), code_align(0), data_align(0),
          return_addr_reg_num(LLDB_INVALID_REGNUM), inst_offset(0),
          inst_length(0), ptr_encoding(0), lsda_addr_encoding(DW_EH_PE_omit),
          personality_loc(LLDB_INVALID_ADDRESS), initial_row() {}
  };

  typedef std::shared_ptr<CIE> CIESP;

  typedef std::map<dw_offset_t, CIESP> cie_map_t;

  // Start address (file address), size, offset of FDE location
  // used for finding an FDE for a given File address; the start address field
  // is
  // an offset into an individual Module.
  typedef RangeDataVector<lldb::addr_t, uint32_t, dw_offset_t> FDEEntryMap;

  bool IsEHFrame() const;

  bool GetFDEEntryByFileAddress(lldb::addr_t file_offset,
                                FDEEntryMap::Entry &fde_entry);

  void GetFDEIndex();

  bool FDEToUnwindPlan(uint32_t offset, Address startaddr,
                       UnwindPlan &unwind_plan);

  const CIE *GetCIE(dw_offset_t cie_offset);

  void GetCFIData();

  // Applies the specified DWARF opcode to the given row. This function handle
  // the commands
  // operates only on a single row (these are the ones what can appear both in
  // CIE and in FDE).
  // Returns true if the opcode is handled and false otherwise.
  bool HandleCommonDwarfOpcode(uint8_t primary_opcode, uint8_t extended_opcode,
                               int32_t data_align, lldb::offset_t &offset,
                               UnwindPlan::Row &row);

  ObjectFile &m_objfile;
  lldb::SectionSP m_section_sp;
  lldb::RegisterKind m_reg_kind;
  Flags m_flags;
  cie_map_t m_cie_map;

  DataExtractor m_cfi_data;
  bool m_cfi_data_initialized; // only copy the section into the DE once

  FDEEntryMap m_fde_index;
  bool m_fde_index_initialized; // only scan the section for FDEs once
  std::mutex m_fde_index_mutex; // and isolate the thread that does it

  bool m_is_eh_frame;

  CIESP
  ParseCIE(const uint32_t cie_offset);
};

} // namespace lldb_private

#endif // liblldb_DWARFCallFrameInfo_h_