aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins/Process/Utility/RegisterContextLLDB.h
blob: cb22eedd560a3a7312965c48207dd7567aa834a4 (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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
//===-- RegisterContextLLDB.h --------------------------------------------*- C++
//-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef lldb_RegisterContextLLDB_h_
#define lldb_RegisterContextLLDB_h_

// C Includes
// C++ Includes
#include <vector>

// Other libraries and framework includes
// Project includes
#include "UnwindLLDB.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/RegisterNumber.h"
#include "lldb/lldb-private.h"

namespace lldb_private {

class UnwindLLDB;

class RegisterContextLLDB : public lldb_private::RegisterContext {
public:
  typedef std::shared_ptr<RegisterContextLLDB> SharedPtr;

  RegisterContextLLDB(lldb_private::Thread &thread, const SharedPtr &next_frame,
                      lldb_private::SymbolContext &sym_ctx,
                      uint32_t frame_number,
                      lldb_private::UnwindLLDB &unwind_lldb);

  ~RegisterContextLLDB() override = default;

  void InvalidateAllRegisters() override;

  size_t GetRegisterCount() override;

  const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;

  size_t GetRegisterSetCount() override;

  const lldb_private::RegisterSet *GetRegisterSet(size_t reg_set) override;

  bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
                    lldb_private::RegisterValue &value) override;

  bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
                     const lldb_private::RegisterValue &value) override;

  bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;

  bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;

  uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
                                               uint32_t num) override;

  bool IsValid() const;

  bool IsTrapHandlerFrame() const;

  bool GetCFA(lldb::addr_t &cfa);

  bool GetStartPC(lldb::addr_t &start_pc);

  bool ReadPC(lldb::addr_t &start_pc);

private:
  enum FrameType {
    eNormalFrame,
    eTrapHandlerFrame,
    eDebuggerFrame, // a debugger inferior function call frame; we get caller's
                    // registers from debugger
    eSkipFrame,     // The unwind resulted in a bogus frame but may get back on
                    // track so we don't want to give up yet
    eNotAValidFrame // this frame is invalid for some reason - most likely it is
                    // past the top (end) of the stack
  };

  // UnwindLLDB needs to pass around references to RegisterLocations
  friend class UnwindLLDB;

  // Returns true if we have an unwind loop -- the same stack frame unwinding
  // multiple times.
  bool CheckIfLoopingStack();

  // Indicates whether this frame is frame zero -- the currently
  // executing frame -- or not.
  bool IsFrameZero() const;

  void InitializeZerothFrame();

  void InitializeNonZerothFrame();

  SharedPtr GetNextFrame() const;

  SharedPtr GetPrevFrame() const;

  // A SkipFrame occurs when the unwind out of frame 0 didn't go right -- we've
  // got one bogus frame at frame #1.
  // There is a good chance we'll get back on track if we follow the frame
  // pointer chain (or whatever is appropriate
  // on this ABI) so we allow one invalid frame to be in the stack.  Ideally
  // we'll mark this frame specially at some
  // point and indicate to the user that the unwinder had a hiccup.  Often when
  // this happens we will miss a frame of
  // the program's actual stack in the unwind and we want to flag that for the
  // user somehow.
  bool IsSkipFrame() const;

  //------------------------------------------------------------------
  /// Determines if a SymbolContext is a trap handler or not
  ///
  /// Given a SymbolContext, determines if this is a trap handler function
  /// aka asynchronous signal handler.
  ///
  /// @return
  ///     Returns true if the SymbolContext is a trap handler.
  //------------------------------------------------------------------
  bool IsTrapHandlerSymbol(lldb_private::Process *process,
                           const lldb_private::SymbolContext &m_sym_ctx) const;

  // Provide a location for where THIS function saved the CALLER's register
  // value
  // Or a frame "below" this one saved it, i.e. a function called by this one,
  // preserved a register that this
  // function didn't modify/use.
  //
  // The RegisterLocation type may be set to eRegisterNotAvailable -- this will
  // happen for a volatile register
  // being queried mid-stack.  Instead of floating frame 0's contents of that
  // register up the stack (which may
  // or may not be the value of that reg when the function was executing), we
  // won't return any value.
  //
  // If a non-volatile register (a "preserved" register) is requested mid-stack
  // and no frames "below" the requested
  // stack have saved the register anywhere, it is safe to assume that frame 0's
  // register values are still the same
  // as the requesting frame's.
  lldb_private::UnwindLLDB::RegisterSearchResult
  SavedLocationForRegister(uint32_t lldb_regnum,
                           lldb_private::UnwindLLDB::RegisterLocation &regloc);

  bool ReadRegisterValueFromRegisterLocation(
      lldb_private::UnwindLLDB::RegisterLocation regloc,
      const lldb_private::RegisterInfo *reg_info,
      lldb_private::RegisterValue &value);

  bool WriteRegisterValueToRegisterLocation(
      lldb_private::UnwindLLDB::RegisterLocation regloc,
      const lldb_private::RegisterInfo *reg_info,
      const lldb_private::RegisterValue &value);

  //------------------------------------------------------------------
  /// If the unwind has to the caller frame has failed, try something else
  ///
  /// If lldb is using an assembly language based UnwindPlan for a frame and
  /// the unwind to the caller frame fails, try falling back to a generic
  /// UnwindPlan (architecture default unwindplan) to see if that might work
  /// better.  This is mostly helping to work around problems where the
  /// assembly language inspection fails on hand-written assembly code.
  ///
  /// @return
  ///     Returns true if a fallback unwindplan was found & was installed.
  //------------------------------------------------------------------
  bool TryFallbackUnwindPlan();

  //------------------------------------------------------------------
  /// Switch to the fallback unwind plan unconditionally without any safety
  /// checks that it is providing better results than the normal unwind plan.
  ///
  /// The only time it is valid to call this method is if the full unwindplan is
  /// found to be fundamentally incorrect/impossible.
  ///
  /// Returns true if it was able to install the fallback unwind plan.
  //------------------------------------------------------------------
  bool ForceSwitchToFallbackUnwindPlan();

  // Get the contents of a general purpose (address-size) register for this
  // frame
  // (usually retrieved from the next frame)
  bool ReadGPRValue(lldb::RegisterKind register_kind, uint32_t regnum,
                    lldb::addr_t &value);

  bool ReadGPRValue(const RegisterNumber &reg_num, lldb::addr_t &value);

  // Get the CFA register for a given frame.
  bool ReadCFAValueForRow(lldb::RegisterKind register_kind,
                          const UnwindPlan::RowSP &row, lldb::addr_t &value);

  lldb::UnwindPlanSP GetFastUnwindPlanForFrame();

  lldb::UnwindPlanSP GetFullUnwindPlanForFrame();

  void UnwindLogMsg(const char *fmt, ...) __attribute__((format(printf, 2, 3)));

  void UnwindLogMsgVerbose(const char *fmt, ...)
      __attribute__((format(printf, 2, 3)));

  bool IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp,
                                     int &valid_pc_offset);

  lldb_private::Thread &m_thread;

  ///
  // The following tell us how to retrieve the CALLER's register values (ie the
  // "previous" frame, aka the frame above)
  // i.e. where THIS frame saved them
  ///

  lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL
  lldb::UnwindPlanSP m_full_unwind_plan_sp;
  lldb::UnwindPlanSP m_fallback_unwind_plan_sp; // may be NULL

  bool m_all_registers_available; // Can we retrieve all regs or just
                                  // nonvolatile regs?
  int m_frame_type;               // enum FrameType

  lldb::addr_t m_cfa;
  lldb_private::Address m_start_pc;
  lldb_private::Address m_current_pc;

  int m_current_offset; // how far into the function we've executed; -1 if
                        // unknown
                        // 0 if no instructions have been executed yet.

  int m_current_offset_backed_up_one; // how far into the function we've
                                      // executed; -1 if unknown
  // 0 if no instructions have been executed yet.
  // On architectures where the return address on the stack points
  // to the instruction after the CALL, this value will have 1
  // subtracted from it.  Else a function that ends in a CALL will
  // have an offset pointing into the next function's address range.
  // m_current_pc has the actual address of the "current" pc.

  lldb_private::SymbolContext &m_sym_ctx;
  bool m_sym_ctx_valid; // if ResolveSymbolContextForAddress fails, don't try to
                        // use m_sym_ctx

  uint32_t m_frame_number; // What stack frame this RegisterContext is

  std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation>
      m_registers; // where to find reg values for this frame

  lldb_private::UnwindLLDB &m_parent_unwind; // The UnwindLLDB that is creating
                                             // this RegisterContextLLDB

  //------------------------------------------------------------------
  // For RegisterContextLLDB only
  //------------------------------------------------------------------

  DISALLOW_COPY_AND_ASSIGN(RegisterContextLLDB);
};

} // namespace lldb_private

#endif // lldb_RegisterContextLLDB_h_