Fix ARM stack walking (#559)
[dyninst.git] / stackwalk / src / linux-aarch64-swk.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  *
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  *
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  *
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #include "stackwalk/h/swk_errors.h"
32 #include "stackwalk/h/walker.h"
33 #include "stackwalk/h/basetypes.h"
34 #include "stackwalk/h/procstate.h"
35 #include "stackwalk/h/framestepper.h"
36 #include "stackwalk/h/frame.h"
37
38 #include "stackwalk/src/linuxbsd-swk.h"
39 #include "stackwalk/src/dbgstepper-impl.h"
40
41 #include "common/h/dyn_regs.h"
42 #include "frame.h"
43
44 #include <sys/user.h>
45 #include <sys/ptrace.h>
46 #include <assert.h>
47 #include <errno.h>
48 #include <string.h>
49 #include <sys/ucontext.h>
50
51
52
53 using namespace Dyninst;
54 using namespace Dyninst::Stackwalker;
55
56 bool Walker::createDefaultSteppers()
57 {
58     FrameStepper *stepper;
59     bool result;
60
61     // ARM: this works on ARM.
62     // Need to adjust a variable that stores the length of _start
63     stepper = new BottomOfStackStepper(this);
64     result = addStepper(stepper);
65     if (!result){
66         sw_printf("[%s:%u] - Error adding stepper %p\n", FILE__, __LINE__,
67                   stepper);
68         return false;
69     }else{
70         sw_printf("[%s:%u] - Stepper %p is BottomOfStackStepper\n",
71                   FILE__, __LINE__, stepper);
72     }
73 /*
74     stepper = new DebugStepper(this);
75     result = addStepper(stepper);
76     if (!result){
77         sw_printf("[%s:%u] - Error adding stepper %p\n", FILE__, __LINE__,
78                   stepper);
79         return false;
80     } else{
81         sw_printf("[%s:%u] - Stepper %p is DebugStepper\n",
82                   FILE__, __LINE__, stepper);
83     }
84  */
85     stepper = new FrameFuncStepper(this);
86     result = addStepper(stepper);
87     if (!result) {
88         sw_printf("[%s:%u] - Error adding stepper %p\n", FILE__, __LINE__,
89                   stepper);
90         return false;
91     } else {
92         sw_printf("[%s:%u] - Stepper %p is FrameFuncStepper\n",
93                   FILE__, __LINE__, stepper);
94     }
95     stepper = new SigHandlerStepper(this);
96     result = addStepper(stepper);
97     if (!result) {
98         sw_printf("[%s:%u] - Error adding stepper %p\n", FILE__, __LINE__,
99                   stepper);
100         return false;
101     }else {
102         sw_printf("[%s:%u] - Stepper %p is SigHandlerStepper\n",
103                   FILE__, __LINE__, stepper);
104     }
105
106     return true;
107 }
108
109 bool DebugStepperImpl::isFrameRegister(MachRegister reg)
110 {
111    if (getProcessState()->getAddressWidth() == 4){
112        assert(0);
113       return (reg == aarch64::x29);
114    }
115    else
116       return (reg == aarch64::x29);
117 }
118
119 bool DebugStepperImpl::isStackRegister(MachRegister reg)
120 {
121    if (getProcessState()->getAddressWidth() == 4){
122        assert(0);
123       return (reg == aarch64::sp);
124    }
125    else
126       return (reg == aarch64::sp);
127 }
128
129 static     ucontext_t dummy_context;
130 static int sp_offset = (char*)&(dummy_context.uc_mcontext.sp)       - (char*)&dummy_context;
131 static int fp_offset = (char*)&(dummy_context.uc_mcontext.regs[29]) - (char*)&dummy_context;
132 static int pc_offset = (char*)&(dummy_context.uc_mcontext.pc)       - (char*)&dummy_context;
133
134 gcframe_ret_t SigHandlerStepperImpl::getCallerFrame(const Frame & in,
135                                                     Frame & out)
136 {
137     // This function assumes there is FP in "Frame in"
138     // And assumes that ucontext is the first object on the stack frame
139     bool result;
140
141     Address last_read_sp_addr = 0;
142     Address last_read_sp_val = 0;
143     int addr_size = 8;
144     location_t sp_loc;
145     sp_loc.location = loc_address;
146     sp_loc.val.addr = in.getFP() + sp_offset - sizeof(dummy_context);
147
148     Address sp = 0;
149     sw_printf("In frame sp %lx, fp %lx, pc %lx\n", in.getSP(), in.getFP(), in.getRA());
150     if (last_read_sp_addr != sp_loc.val.addr)
151     {
152         result = getProcessState()->readMem(&sp, sp_loc.val.addr, addr_size);
153         if (!result) {
154             sw_printf("[%s:%u] Unexpected error reading from stack memory 0x%lx for signal frame\n",
155                       FILE__, __LINE__);
156             return gcf_error;
157         }
158         last_read_sp_addr = sp_loc.val.addr;
159         last_read_sp_val = sp;
160     }
161     else {
162         sp = last_read_sp_val;
163     }
164
165
166     location_t fp_loc;
167     Address fp = 0x0;
168     fp_loc.location = loc_address;
169     fp_loc.val.addr = in.getFP() + fp_offset - sizeof(dummy_context);
170     sw_printf("[%s:%u] - SigHandler Reading FP from %lx\n",
171               FILE__, __LINE__, fp_loc.val.addr);
172     result = getProcessState()->readMem(&fp, fp_loc.val.addr, addr_size);
173     if (!result) {
174         sw_printf("[%s:%u] Unexpected error reading from stack memory 0x%lx for signal frame\n",
175                   FILE__, __LINE__);
176         return gcf_error;
177     }
178
179     location_t pc_loc;
180     Address pc = 0x0;
181     pc_loc.location = loc_address;
182     pc_loc.val.addr = in.getFP() + pc_offset - sizeof(dummy_context);
183     sw_printf("[%s:%u] - SigHandler Reading PC from %lx\n",
184               FILE__, __LINE__, pc_loc.val.addr);
185     result = getProcessState()->readMem(&pc, pc_loc.val.addr, addr_size);
186     if (!result) {
187         sw_printf("[%s:%u] Unexpected error reading from stack memory 0x%lx for signal frame\n",
188                   FILE__, __LINE__);
189         return gcf_error;
190     }
191
192     out.setRA((Dyninst::MachRegisterVal) pc);
193     out.setFP((Dyninst::MachRegisterVal) fp);
194     out.setSP((Dyninst::MachRegisterVal) sp);
195     out.setRALocation(pc_loc);
196     out.setFPLocation(fp_loc);
197     out.setSPLocation(sp_loc);
198     out.setNonCall();
199     return gcf_success;
200
201 }