aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins/Process/Utility/RegisterContextLLDB.h
blob: d6ecfeb68caa4afa20ffcfb00321b6889fb463c9 (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
//===-- 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_

#include <vector>

#include "lldb/lldb-private.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Symbol/SymbolContext.h"
#include "UnwindLLDB.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);

    ///
    // pure virtual functions from the base class that we must implement
    ///

    virtual
    ~RegisterContextLLDB () { }

    virtual void
    InvalidateAllRegisters ();

    virtual size_t
    GetRegisterCount ();

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

    virtual size_t
    GetRegisterSetCount ();

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

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

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

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

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

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

    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;

    // 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 ();

    // 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);

    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_