proccontrol: Fix Coverity UNINIT_CTOR errors
[dyninst.git] / proccontrol / src / ppc_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 "proccontrol/src/ppc_process.h"
32 #include "common/src/arch-power.h"
33 #include <string.h>
34 #include <iostream>
35
36 using namespace NS_power;
37 using namespace std;
38
39 ppc_process::ppc_process(Dyninst::PID p, std::string e, std::vector<std::string> a, 
40                          std::vector<std::string> envp, std::map<int, int> f) :
41    int_process(p, e, a, envp, f)
42 {
43 }
44
45 ppc_process::ppc_process(Dyninst::PID pid_, int_process *p) :
46   int_process(pid_, p)
47 {
48 }
49
50 ppc_process::~ppc_process()
51 {
52 }
53
54 unsigned ppc_process::plat_breakpointSize()
55 {
56   return 4;
57 }
58
59 void ppc_process::plat_breakpointBytes(unsigned char *buffer)
60 {
61   buffer[0] = 0x7d;
62   buffer[1] = 0x82;
63   buffer[2] = 0x10;
64   buffer[3] = 0x08;
65 }
66
67 bool ppc_process::plat_breakpointAdvancesPC() const
68 {
69    return false;
70 }
71
72 static bool atomicLoad(const instruction &insn) {
73     return (    (XFORM_OP(insn) == LXop)
74              && (XFORM_XO(insn) == LWARXxop) );
75 }
76
77 static bool atomicStore(const instruction &insn) {
78     return (    (XFORM_OP(insn) == STXop) 
79              && (XFORM_XO(insn) == STWCXxop) );
80 }
81
82 void clear_ss_state_cb(int_thread *thr) {
83    ppc_process *proc = dynamic_cast<ppc_process *>(thr->llproc());
84    proc->cleanupSSOnContinue(thr);
85 }
86
87 void ppc_process::cleanupSSOnContinue(int_thread *thr)
88 {
89    //Clear the PC for this thread
90    map<int_thread *, reg_response::ptr>::iterator i = pcs_for_ss.find(thr);
91    if (i == pcs_for_ss.end())
92       return;
93    pcs_for_ss.erase(i);
94
95    if (!pcs_for_ss.empty()) {
96       //We'll only clear the memory cache if every PC is done SS'ing
97       return;
98    }
99
100    //Clear the memory cache
101    map<Address, mem_response::ptr>::iterator j;
102    for (j = mem_for_ss.begin(); j != mem_for_ss.end(); j++) {
103       assert(j->second->isReady() || j->second->hasError());
104       free(j->second->getBuffer());
105    }
106    mem_for_ss.clear();
107 }
108
109 void ppc_process::registerSSClearCB()
110 {
111    static bool registered_ss_clear_cb = false;
112    if (registered_ss_clear_cb)
113       return;
114    int_thread::addContinueCB(clear_ss_state_cb);
115    registered_ss_clear_cb = true;
116 }
117
118 async_ret_t ppc_process::readPCForSS(int_thread *thr, Address &pc)
119 {
120    ppc_thread *ppc_thr = dynamic_cast<ppc_thread *>(thr);
121    assert(ppc_thr);
122    if (ppc_thr->haveCachedPC(pc))
123       return aret_success;
124
125    if (!plat_needsAsyncIO())
126    {
127       //Fast-track for linu/ppc
128       reg_response::ptr pcResponse = reg_response::createRegResponse();
129       bool result = thr->getRegister(MachRegister::getPC(getTargetArch()), pcResponse);
130       if (!result || pcResponse->hasError()) {
131          pthrd_printf("Error reading PC address to check for emulated single step condition\n");
132          return aret_error;
133       }
134       bool ready = pcResponse->isReady();
135       assert(ready);
136       pc = (Address) pcResponse->getResult();
137       return aret_success;
138    }
139
140    //Store and cache the PC value on AsyncIO platforms (bluegene)
141    registerSSClearCB();
142
143    bool result = true;
144    reg_response::ptr resp;
145    map<int_thread *, reg_response::ptr>::iterator i = pcs_for_ss.find(thr);
146    if (i == pcs_for_ss.end()) {
147       resp = reg_response::createRegResponse();
148       pcs_for_ss[thr] = resp;
149       result = thr->getRegister(MachRegister::getPC(getTargetArch()), resp);
150    }
151    else {
152       resp = i->second;
153    }
154
155    if (!result || resp->hasError()) {
156       pthrd_printf("Error reading PC address to check for emulated single step condition\n");
157       return aret_error;
158    }
159    if (!resp->isReady()) {
160       pthrd_printf("Async return while getting PC for emulated single step test\n");
161       return aret_async;
162    }
163    pc = (Address) resp->getResult();
164    return aret_success;
165 }
166
167 async_ret_t ppc_process::readInsnForSS(Address pc, int_thread *, unsigned int &rawInsn)
168 {
169    if (!plat_needsAsyncIO())
170    {
171       //Fast-track for linux/ppc
172       mem_response::ptr new_resp = mem_response::createMemResponse((char *) &rawInsn, sizeof(unsigned int));
173       bool result = readMem(pc, new_resp);
174       if (!result || new_resp->hasError()) {
175          pthrd_printf("Error during memory read for pc\n");
176          return aret_error;
177       }
178       bool ready = new_resp->isReady();
179       assert(ready);
180       return aret_success;
181    }
182
183    /**
184     * Use larger reads and cache memory buffers when on an asyncIO system (bluegene)
185     **/
186    map<Address, mem_response::ptr>::iterator i;
187    for (i = mem_for_ss.begin(); i != mem_for_ss.end(); i++) {
188       if (pc >= i->first && pc+4 <= i->first + i->second->getSize()) {
189          if (!i->second->isReady()) {
190             pthrd_printf("Returning async form memory read while doing emulated single step test\n");
191             return aret_async;
192          }
193          if (i->second->hasError()) {
194             pthrd_printf("Error during async read of memory during emulated single step test\n");
195             return aret_error;
196          }
197          Offset offset = pc - i->first;
198          memcpy(&rawInsn, i->second->getBuffer() + offset, sizeof(unsigned int));
199          return aret_success;
200       }
201    }
202       
203    unsigned int read_size = plat_getRecommendedReadSize();
204    
205    //Don't read over page boundarys.  Could cause problems if reading from
206    // last executable page.
207    unsigned int page_size = getTargetPageSize();
208    unsigned int page_offset = pc % page_size;
209    if (page_offset + read_size > page_size) {
210       read_size = page_size - page_offset;
211    }
212    assert(read_size >= sizeof(unsigned int));
213
214    char *buffer = (char *) malloc(read_size);
215    mem_response::ptr new_resp = mem_response::createMemResponse(buffer, read_size);
216    bool result = readMem(pc, new_resp);
217    mem_for_ss[pc] = new_resp;
218    if (!result || new_resp->hasError()) {
219       pthrd_printf("Error during async read of memory during emulated single step test\n");
220       return aret_error;
221    }
222    if (!new_resp->isReady()) {
223       pthrd_printf("Returning async from memory read during single step test\n");
224       return aret_async;
225    }
226    memcpy(&rawInsn, new_resp->getBuffer(), sizeof(unsigned int));
227    return aret_success;
228 }
229
230 async_ret_t ppc_process::plat_needsEmulatedSingleStep(int_thread *thr, vector<Address> &addrResult) {
231    assert(thr->singleStep());
232    
233    pthrd_printf("Checking for atomic instruction sequence before single step\n");
234     
235    /* 
236     * We need an emulated single step to single step an atomic
237     * instruction sequence. The sequence looks something like this:
238     *
239     * lwarx
240     * ...
241     * stwcx.
242     * <breapoint>
243     *
244     * We need to set the breakpoint at the instruction immediately after
245     * stwcx.
246     */
247    Address pc;
248    async_ret_t aresult = readPCForSS(thr, pc);
249    if (aresult == aret_error || aresult == aret_async)
250       return aresult;
251
252     // Check if the next instruction is a lwarx
253     // If it is, scan forward until the terminating stwcx.
254     bool foundEnd = false;
255     bool sequenceStarted = false;
256     int maxSequenceCount = 24; // arbitrary 
257     int currentCount = 0;
258     do {
259         // Read the current instruction
260         unsigned int rawInsn;
261         aresult = readInsnForSS(pc, thr, rawInsn);
262         if (aresult == aret_error || aresult == aret_async)
263            return aresult;
264
265         // Decode the current instruction
266         instruction insn(rawInsn);
267         if( atomicLoad(insn) ) {
268             sequenceStarted = true;
269             pthrd_printf("Found the start of an atomic instruction sequence at 0x%lx\n", pc);
270         }else{
271             if( !sequenceStarted ) break;
272         }
273
274         if( atomicStore(insn) && sequenceStarted ) {
275             foundEnd = true;
276         }
277
278         // For control flow instructions, assume target is outside atomic instruction sequence
279         // and place breakpoint there as well
280         Address cfTarget = insn.getTarget(pc);
281         if( cfTarget != 0 && sequenceStarted && !foundEnd ) {
282             addrResult.push_back(cfTarget);
283         }
284
285         currentCount++;
286         pc += 4;
287     }while( !foundEnd && currentCount < maxSequenceCount );
288
289     // The breakpoint should be set at the instruction following the sequence
290     if( foundEnd ) {
291         addrResult.push_back(pc);
292         pthrd_printf("Atomic instruction sequence ends at 0x%lx\n", pc);
293     }else if( sequenceStarted || addrResult.size() ) {
294         addrResult.clear();
295         pthrd_printf("Failed to find end of atomic instruction sequence\n");
296         return aret_error;
297     }else{
298         pthrd_printf("No atomic instruction sequence found, safe to single step\n");
299     }
300
301     return aret_success;
302 }
303
304 void ppc_process::plat_getEmulatedSingleStepAsyncs(int_thread *, std::set<response::ptr> resps)
305 {
306    map<int_thread *, reg_response::ptr>::iterator i;
307    for (i = pcs_for_ss.begin(); i != pcs_for_ss.end(); i++) {
308       if (!i->second->isReady()) {
309          resps.insert(i->second);
310       }
311    }
312    map<Address, mem_response::ptr>::iterator j;
313    for (j = mem_for_ss.begin(); j != mem_for_ss.end(); j++) {
314       if (!j->second->isReady()) {
315          resps.insert(j->second);
316       }
317    }
318 }
319
320 bool ppc_process::plat_convertToBreakpointAddress(Address &, int_thread *) {
321    return true;
322 }
323
324 bool ppc_process::plat_needsPCSaveBeforeSingleStep() 
325 {
326    return true;
327 }
328
329 ppc_thread::ppc_thread(int_process *p, Dyninst::THR_ID t, Dyninst::LWP l) :
330    int_thread(p, t, l), have_cached_pc(false), cached_pc(0)
331 {
332 }
333
334 ppc_thread::~ppc_thread()
335 {
336 }
337
338 bool ppc_thread::rmHWBreakpoint(hw_breakpoint *,
339                                 bool,
340                                 std::set<response::ptr> &,
341                                 bool &)
342 {
343    return false;
344 }
345
346 bool ppc_thread::addHWBreakpoint(hw_breakpoint *,
347                                  bool,
348                                  std::set<response::ptr> &,
349                                  bool &)
350 {
351    return false;
352 }
353
354 unsigned ppc_thread::hwBPAvail(unsigned)
355 {
356    return 0;
357 }
358
359 EventBreakpoint::ptr ppc_thread::decodeHWBreakpoint(response::ptr &,
360                                                     bool,
361                                                     Dyninst::MachRegisterVal)
362 {
363    return EventBreakpoint::ptr();
364 }
365
366 bool ppc_thread::bpNeedsClear(hw_breakpoint *)
367 {
368    return false;
369 }
370
371 void ppc_thread::setCachedPC(Address pc)
372 {
373    cached_pc = pc;
374    have_cached_pc = true;
375 }
376
377 void ppc_thread::clearCachedPC()
378 {
379    have_cached_pc = false;
380 }
381
382 bool ppc_thread::haveCachedPC(Address &pc)
383 {
384    if (!have_cached_pc)
385       return false;
386    pc = cached_pc;
387    return true;
388 }