fix warning defines
[dyninst.git] / proccontrol / src / arm_process.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 <string.h>
32 #include <iostream>
33 #include "proccontrol/src/arm_process.h"
34 #include "common/src/arch-aarch64.h"
35
36 using namespace NS_aarch64;
37 using namespace std;
38
39 //constructors, blank functions
40 arm_process::arm_process(Dyninst::PID p, std::string e, std::vector<std::string> a,
41                          std::vector<std::string> envp, std::map<int, int> f) :
42    int_process(p, e, a, envp, f)
43 {
44 }
45
46 arm_process::arm_process(Dyninst::PID pid_, int_process *p) :
47   int_process(pid_, p)
48 {
49 }
50
51 arm_process::~arm_process()
52 {
53 }
54
55 unsigned arm_process::plat_breakpointSize()
56 {
57   //This size is the number of bytes of one
58   //trap instruction. In aarch64, this is BRK
59   //which stands for breakpoint, with a normal
60   //length of 32bits == 4bytes
61   return 4;
62 }
63
64 void arm_process::plat_breakpointBytes(unsigned char *buffer)
65 {
66   //memory oppucation:
67   //high---low addr
68   //[3] [2] [1] [0]
69   //this is a BRK instruction in aarch64, which incurs a
70   //software exception, the encoding is
71   //0b1101_0100_001x_xxxx_xxxx_xxxx_xxx0_0000
72   //(x is for imm16)
73   //the following instruction stands for
74   //BRK #0;
75   buffer[0] = 0x00;
76   buffer[1] = 0x00;
77   buffer[2] = 0x20;
78   buffer[3] = 0xd4;
79 }
80
81 bool arm_process::plat_breakpointAdvancesPC() const
82 {
83    //as doc says, arm will return to the interrupted intruction
84    return false;
85 }
86
87
88 bool arm_process::plat_convertToBreakpointAddress(Address &, int_thread *) {
89    return true;
90 }
91
92 // The following a few of functions are used for emulated
93 // singlestep. The scenario is quite similiar to what happens
94 // on PPC.
95 // ----
96 // ldaxr
97 // ...
98 // stxr
99 // ----
100 //
101
102 // to check if this insn is exclusive load/store
103 static bool atomicLoad(const instruction &insn) {
104     return insn.isAtomicLoad();
105 }
106
107 static bool atomicStore(const instruction &insn) {
108     return insn.isAtomicStore();
109 }
110
111 static void clear_ss_state_cb(int_thread *thr) {
112    arm_process *proc = dynamic_cast<arm_process *>(thr->llproc());
113    proc->cleanupSSOnContinue(thr);
114 }
115
116 void arm_process::cleanupSSOnContinue(int_thread *thr)
117 {
118    //Clear the PC for this thread
119    map<int_thread *, reg_response::ptr>::iterator i = pcs_for_ss.find(thr);
120    if (i == pcs_for_ss.end())
121       return;
122    pcs_for_ss.erase(i);
123
124    if (!pcs_for_ss.empty()) {
125       //We'll only clear the memory cache if every PC is done SS'ing
126       return;
127    }
128
129    //Clear the memory cache
130    map<Address, mem_response::ptr>::iterator j;
131    for (j = mem_for_ss.begin(); j != mem_for_ss.end(); j++) {
132       assert(j->second->isReady() || j->second->hasError());
133       free(j->second->getBuffer());
134    }
135    mem_for_ss.clear();
136 }
137
138 void arm_process::registerSSClearCB()
139 {
140    static bool registered_ss_clear_cb = false;
141    if (registered_ss_clear_cb)
142       return;
143    int_thread::addContinueCB(clear_ss_state_cb);
144    registered_ss_clear_cb = true;
145 }
146
147 async_ret_t arm_process::readPCForSS(int_thread *thr, Address &pc)
148 {
149    arm_thread *arm_thr = dynamic_cast<arm_thread *>(thr);
150    assert(arm_thr);
151    if (arm_thr->haveCachedPC(pc))
152       return aret_success;
153
154    if (!plat_needsAsyncIO())
155    {
156       //Fast-track for linux/arm
157       reg_response::ptr pcResponse = reg_response::createRegResponse();
158       bool result = thr->getRegister(MachRegister::getPC(getTargetArch()), pcResponse);
159       if (!result || pcResponse->hasError()) {
160          pthrd_printf("Error reading PC address to check for emulated single step condition\n");
161          return aret_error;
162       }
163       bool ready = pcResponse->isReady();
164       assert(ready);
165       if(!ready) return aret_error;
166       pc = (Address) pcResponse->getResult();
167       return aret_success;
168    }
169
170    //Store and cache the PC value on AsyncIO platforms (bluegene)
171    registerSSClearCB();
172
173    bool result = true;
174    reg_response::ptr resp;
175    map<int_thread *, reg_response::ptr>::iterator i = pcs_for_ss.find(thr);
176    if (i == pcs_for_ss.end()) {
177       resp = reg_response::createRegResponse();
178       pcs_for_ss[thr] = resp;
179       result = thr->getRegister(MachRegister::getPC(getTargetArch()), resp);
180    }
181    else {
182       resp = i->second;
183    }
184
185    if (!result || resp->hasError()) {
186       pthrd_printf("Error reading PC address to check for emulated single step condition\n");
187       return aret_error;
188    }
189    if (!resp->isReady()) {
190       pthrd_printf("Async return while getting PC for emulated single step test\n");
191       return aret_async;
192    }
193    pc = (Address) resp->getResult();
194    return aret_success;
195 }
196
197 async_ret_t arm_process::readInsnForSS(Address pc, int_thread *, unsigned int &rawInsn)
198 {
199    if (!plat_needsAsyncIO())
200    {
201       //Fast-track for linux/arm
202       mem_response::ptr new_resp = mem_response::createMemResponse((char *) &rawInsn, sizeof(unsigned int));
203       bool result = readMem(pc, new_resp);
204       if (!result || new_resp->hasError()) {
205          pthrd_printf("Error during memory read for pc\n");
206          return aret_error;
207       }
208       bool ready = new_resp->isReady();
209       assert(ready);
210       if(!ready) return aret_error;
211       return aret_success;
212    }
213
214    /**
215     * Use larger reads and cache memory buffers when on an asyncIO system (bluegene)
216     **/
217    map<Address, mem_response::ptr>::iterator i;
218    for (i = mem_for_ss.begin(); i != mem_for_ss.end(); i++) {
219       if (pc >= i->first && pc+4 <= i->first + i->second->getSize()) {
220          if (!i->second->isReady()) {
221             pthrd_printf("Returning async form memory read while doing emulated single step test\n");
222             return aret_async;
223          }
224          if (i->second->hasError()) {
225             pthrd_printf("Error during async read of memory during emulated single step test\n");
226             return aret_error;
227          }
228          Offset offset = pc - i->first;
229          memcpy(&rawInsn, i->second->getBuffer() + offset, sizeof(unsigned int));
230          return aret_success;
231       }
232    }
233
234    unsigned int read_size = plat_getRecommendedReadSize();
235
236    // Don't read over page boundarys.  Could cause problems if reading from
237    // last executable page.
238    unsigned int page_size = getTargetPageSize();
239    unsigned int page_offset = pc % page_size;
240    if (page_offset + read_size > page_size) {
241       read_size = page_size - page_offset;
242    }
243    assert(read_size >= sizeof(unsigned int));
244
245    char *buffer = (char *) malloc(read_size);
246    mem_response::ptr new_resp = mem_response::createMemResponse(buffer, read_size);
247    bool result = readMem(pc, new_resp);
248    mem_for_ss[pc] = new_resp;
249    if (!result || new_resp->hasError()) {
250       pthrd_printf("Error during async read of memory during emulated single step test\n");
251       return aret_error;
252    }
253    if (!new_resp->isReady()) {
254       pthrd_printf("Returning async from memory read during single step test\n");
255       return aret_async;
256    }
257    memcpy(&rawInsn, new_resp->getBuffer(), sizeof(unsigned int));
258    return aret_success;
259 }
260
261 async_ret_t arm_process::plat_needsEmulatedSingleStep(int_thread *thr, std::vector<Address> &addrResult) {
262    assert(thr->singleStep());
263
264    pthrd_printf("Checking for atomic instruction sequence before single step\n");
265
266    /*
267     * We need an emulated single step to single step an atomic
268     * instruction sequence. The sequence looks something like this:
269     *
270     * lwarx
271     * ...
272     * stwcx.
273     * <breapoint>
274     *
275     * We need to set the breakpoint at the instruction immediately after
276     * stwcx.
277     */
278    Address pc;
279    async_ret_t aresult = readPCForSS(thr, pc);
280    if (aresult == aret_error || aresult == aret_async)
281       return aresult;
282
283     // Check if the next instruction is a lwarx
284     // If it is, scan forward until the terminating stwcx.
285     bool foundEnd = false;
286     bool sequenceStarted = false;
287     int maxSequenceCount = 24; // arbitrary
288     int currentCount = 0;
289     do {
290         // Read the current instruction
291         unsigned int rawInsn;
292         aresult = readInsnForSS(pc, thr, rawInsn);
293         if (aresult == aret_error || aresult == aret_async)
294            return aresult;
295
296         // Decode the current instruction
297         instruction insn(rawInsn);
298         if( atomicLoad(insn) ) {
299             sequenceStarted = true;
300             pthrd_printf("Found the start of an atomic instruction sequence at 0x%lx\n", pc);
301         }else{
302             if( !sequenceStarted ) break;
303         }
304
305         if( atomicStore(insn) && sequenceStarted ) {
306             foundEnd = true;
307         }
308
309         // For control flow instructions, assume target is outside atomic instruction sequence
310         // and place breakpoint there as well
311         // First check if is branch reg instruction.
312         Address cfTarget;
313         if( insn.isBranchReg() ){
314 //#warning "Test cases don't cover this type of instruction. Potential bugs here.\n"
315             pthrd_printf("ARM-DEBUG: find Branch Reg instruction, going to retrieve the target address.\n");
316             // get reg value from the target proc
317
318             unsigned regNum = insn.getTargetReg();
319
320             reg_response::ptr Response = reg_response::createRegResponse();
321             bool result = thr->getRegister(MachRegister::getArchReg(regNum, Arch_aarch64), Response);
322             if (!result || Response->hasError()) {
323                pthrd_printf("Error reading PC address to check for emulated single step condition\n");
324                return aret_error;
325             }
326             bool ready = Response->isReady();
327             assert(ready);
328             if(!ready) return aret_error;
329
330             cfTarget = (Address) Response->getResult();
331         }else{ // return target address by calculating the offset and pc
332             cfTarget = insn.getTarget(pc);
333         }
334         if( cfTarget != 0 && sequenceStarted && !foundEnd ) {
335             addrResult.push_back(cfTarget);
336         }
337
338         currentCount++;
339         pc += 4;
340     }while( !foundEnd && currentCount < maxSequenceCount );
341
342     // The breakpoint should be set at the instruction following the sequence
343     if( foundEnd ) {
344         addrResult.push_back(pc);
345         pthrd_printf("Atomic instruction sequence ends at 0x%lx\n", pc);
346     }else if( sequenceStarted || addrResult.size() ) {
347         addrResult.clear();
348         pthrd_printf("Failed to find end of atomic instruction sequence\n");
349         return aret_error;
350     }else{
351         pthrd_printf("No atomic instruction sequence found, safe to single step\n");
352     }
353
354     return aret_success;
355 }
356
357 void arm_process::plat_getEmulatedSingleStepAsyncs(int_thread *, std::set<response::ptr> resps)
358 {
359    map<int_thread *, reg_response::ptr>::iterator i;
360    for (i = pcs_for_ss.begin(); i != pcs_for_ss.end(); i++) {
361       if (!i->second->isReady()) {
362          resps.insert(i->second);
363       }
364    }
365    map<Address, mem_response::ptr>::iterator j;
366    for (j = mem_for_ss.begin(); j != mem_for_ss.end(); j++) {
367       if (!j->second->isReady()) {
368          resps.insert(j->second);
369       }
370    }
371 }
372
373 // ------------------------------------
374 // arm thread functions implementations
375
376 arm_thread::arm_thread(int_process *p, Dyninst::THR_ID t, Dyninst::LWP l) :
377    int_thread(p, t, l), have_cached_pc(false), cached_pc(0)
378 {
379 }
380
381 arm_thread::~arm_thread()
382 {
383 }
384
385 //#warning "HWBreakpoint is not supported now."
386 bool arm_thread::rmHWBreakpoint(hw_breakpoint *,
387                                 bool,
388                                 std::set<response::ptr> &,
389                                 bool &)
390 {
391     return false;
392 }
393
394 bool arm_thread::addHWBreakpoint(hw_breakpoint *,
395                                  bool,
396                                  std::set<response::ptr> &,
397                                  bool &)
398 {
399     return false;
400 }
401
402 unsigned arm_thread::hwBPAvail(unsigned)
403 {
404     return 0;
405 }
406
407 EventBreakpoint::ptr arm_thread::decodeHWBreakpoint(response::ptr &,
408                                                     bool,
409                                                     Dyninst::MachRegisterVal)
410 {
411     return EventBreakpoint::ptr();
412 }
413
414 bool arm_thread::bpNeedsClear(hw_breakpoint *)
415 {
416         assert(0); //not implemented
417     return false;
418 }
419
420 void arm_thread::setCachedPC(Address pc)
421 {
422     //what is cached PC?
423     cached_pc = pc;
424     have_cached_pc = true;
425 }
426
427 void arm_thread::clearCachedPC()
428 {
429     have_cached_pc = false;
430 }
431
432 bool arm_thread::haveCachedPC(Address &pc)
433 {
434     if (!have_cached_pc)
435         return false;
436     pc = cached_pc;
437     return true;
438 }