Fix startup failure in test1_1 on linux, PCEventMuxer::wait was returning NoEvent...
[dyninst.git] / dyninstAPI / src / pcEventMuxer.C
1 /*
2  * Copyright (c) 1996-2010 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31 #include "pcEventMuxer.h"
32 #include "pcEventHandler.h"
33 #include "BPatch.h"
34 #include "debug.h"
35 #include "eventLock.h"
36 #include "os.h"
37 #include "dynProcess.h"
38 #include "mapped_object.h"
39 #include "registerSpace.h"
40 #include "RegisterConversion.h"
41 #include "function.h"
42
43 #include "proccontrol/h/Mailbox.h"
44 #include "proccontrol/h/PCErrors.h"
45
46 #include <set>
47 #include <queue>
48 #include <vector>
49
50 using namespace Dyninst;
51 using namespace ProcControlAPI;
52
53 PCEventMuxer PCEventMuxer::muxer_;
54 Process::cb_ret_t PCEventMuxer::ret_stopped(Process::cbProcStop, Process::cbProcStop);
55 Process::cb_ret_t PCEventMuxer::ret_continue(Process::cbProcContinue, Process::cbProcContinue);
56 Process::cb_ret_t PCEventMuxer::ret_default(Process::cbDefault, Process::cbDefault);
57
58 PCEventMuxer::PCEventMuxer() : callbacksRegistered_(false) {
59 };
60
61 bool PCEventMuxer::start() {
62         if (muxer().started_) return true;
63
64         // Register callbacks with ProcControl
65         if (!muxer().registerCallbacks()) {
66                 assert(0 && "Unable to register callbacks with ProcControl, fatal error");
67         }
68
69         // Spawn off a thread to do the actual work
70         // For testing, don't do this. We'll just be slower to respond.
71         //muxer().thrd_.spawn((DThread::initial_func_t) PCEventMuxer::main, NULL);
72         return true;
73 }
74
75 PCEventMuxer::WaitResult PCEventMuxer::wait(bool block) {
76         return muxer().wait_internal(block);
77 }
78
79 PCEventMuxer::WaitResult PCEventMuxer::wait_internal(bool block) {
80         proccontrol_printf("[%s/%d]: PCEventMuxer waiting for events, %s\n",
81                         FILE__, __LINE__, (block ? "blocking" : "non-blocking"));
82         if (!block) {
83                 Process::handleEvents(false);
84                 proccontrol_printf("[%s:%d] after PC event handling, %d events in mailbox\n", FILE__, __LINE__, mailbox_.size());
85                 while (mailbox_.size()) {
86                         EventPtr ev = dequeue(false);
87                         if (!ev) return NoEvents;
88                         if (!handle(ev)) return Error;
89                 }
90         }
91         else {
92                 // It's really annoying from a user design POV that ProcControl methods can
93                 // trigger callbacks; it means that we can't just block here, because we may
94                 // have _already_ gotten a callback and just not finished processing...
95                 if (mailbox_.size() == 0) {
96                         Process::handleEvents(true);
97                 }
98                 proccontrol_printf("[%s:%d] after PC event handling, %d events in mailbox\n", FILE__, __LINE__, mailbox_.size());
99                 EventPtr ev = dequeue(false);
100       if (!ev) {
101          proccontrol_printf("[%s:%u] - PCEventMuxer::wait is returning NoEvents\n", FILE__, __LINE__);
102          return NoEvents;
103       }
104       if (!handle(ev)) {
105          proccontrol_printf("[%s:%u] - PCEventMuxer::wait is returning error after event handling\n", FILE__, __LINE__);
106          return Error;
107       }
108         }
109         return EventsReceived;
110 }
111
112 bool PCEventMuxer::handle(EventPtr ev) {
113         // Find the correct PCEventHandler and dispatch
114         return PCEventHandler::handle(ev);
115 }
116
117 DThread::dthread_ret_t PCEventMuxer::main(void *) {
118         // Loop on wait, decode, handle/enqueue until termination
119         // Since we're callback-based, the decode and handle/enqueue will be taken care of
120         // by the callback functions. 
121         while(1) {
122                 if (!Process::handleEvents(true)) {
123                         // Complain
124                         proccontrol_printf("%s[%d]: error returned by Process::handleEvents: %s\n",
125                                 FILE__, __LINE__, getLastErrorMsg());
126                         continue;
127                 }
128         }
129
130         return DTHREAD_RET_VAL;
131 }
132
133 bool PCEventMuxer::registerCallbacks() {
134         if (callbacksRegistered_) return true;
135
136         bool ret = true;
137
138         ret &= Process::registerEventCallback(EventType(EventType::Any, EventType::Crash), defaultCallback);
139         ret &= Process::registerEventCallback(EventType(EventType::Any, EventType::ForceTerminate), defaultCallback);
140         ret &= Process::registerEventCallback(EventType(EventType::Any, EventType::ThreadCreate), threadCreateCallback);
141         ret &= Process::registerEventCallback(EventType(EventType::Any, EventType::ThreadDestroy), defaultCallback);
142         ret &= Process::registerEventCallback(EventType(EventType::Any, EventType::Signal), signalCallback);
143         ret &= Process::registerEventCallback(EventType(EventType::Any, EventType::Library), defaultCallback);
144         ret &= Process::registerEventCallback(EventType(EventType::Any, EventType::Breakpoint), breakpointCallback);
145         ret &= Process::registerEventCallback(EventType(EventType::Any, EventType::RPC), RPCCallback);
146         ret &= Process::registerEventCallback(EventType(EventType::Any, EventType::SingleStep), defaultCallback);
147
148         // Fork/exec/exit
149         if (useCallback(EventType(EventType::Pre, EventType::Exit))) {
150                 ret &= Process::registerEventCallback(EventType(EventType::Pre, EventType::Exit), exitCallback);
151         }
152         if (useCallback(EventType(EventType::Post, EventType::Exit))) {
153                 ret &= Process::registerEventCallback(EventType(EventType::Post, EventType::Exit), exitCallback);
154         }
155         if (useCallback(EventType(EventType::Pre, EventType::Fork))) {
156                 ret &= Process::registerEventCallback(EventType(EventType::Pre, EventType::Fork), defaultCallback);
157         }
158         if (useCallback(EventType(EventType::Post, EventType::Fork))) {
159                 ret &= Process::registerEventCallback(EventType(EventType::Post, EventType::Fork), defaultCallback);
160         }
161         if (useCallback(EventType(EventType::Pre, EventType::Exec))) {
162                 ret &= Process::registerEventCallback(EventType(EventType::Pre, EventType::Exit), defaultCallback);
163         }
164         if (useCallback(EventType(EventType::Post, EventType::Exec))) {
165                 ret &= Process::registerEventCallback(EventType(EventType::Post, EventType::Exit), defaultCallback);
166         }
167
168
169         callbacksRegistered_ = ret;
170         return ret;
171 };
172
173 // Apologies for the #define, but I get tired of copying the same text over and over, and since this has
174 // a shortcut return it can't be a subfunction. 
175 #define INITIAL_MUXING \
176         PCProcess *process = static_cast<PCProcess *>(ev->getProcess()->getData()); \
177     proccontrol_printf("%s[%d]: Begin callbackMux, process pointer = %p\n", FILE__, __LINE__, process); \
178     if( process == NULL ) { \
179             proccontrol_printf("%s[%d]: NULL process = default/default\n", FILE__, __LINE__); \
180         return Process::cb_ret_t(Process::cbDefault, Process::cbDefault); \
181     } \
182     Process::cb_ret_t ret = ret_stopped; 
183
184 #define DEFAULT_RETURN \
185         PCEventMuxer &m = PCEventMuxer::muxer(); \
186         m.enqueue(ev); \
187         return ret;
188
189
190 PCEventMuxer::cb_ret_t PCEventMuxer::defaultCallback(EventPtr ev) {
191         INITIAL_MUXING;
192
193         DEFAULT_RETURN;
194 }
195
196
197 PCEventMuxer::cb_ret_t PCEventMuxer::exitCallback(EventPtr ev) {
198         INITIAL_MUXING;
199         proccontrol_printf("[%s:%d] Exit callback\n", FILE__, __LINE__);
200         if (ev->getEventType().time() == EventType::Post) {
201                 ret = ret_default;
202         }
203         DEFAULT_RETURN;
204 }
205
206 PCEventMuxer::cb_ret_t PCEventMuxer::crashCallback(EventPtr ev) {
207         INITIAL_MUXING;
208
209         if (ev->getEventType().time() != EventType::Pre) {
210                 ret = ret_default;
211         }
212         DEFAULT_RETURN;
213 }
214
215 PCEventMuxer::cb_ret_t PCEventMuxer::signalCallback(EventPtr ev) {
216         INITIAL_MUXING;
217
218         EventSignal::const_ptr evSignal = ev->getEventSignal();
219
220         if (!PCEventHandler::isKillSignal(evSignal->getSignal())) {
221                 evSignal->clearThreadSignal();
222         }
223         DEFAULT_RETURN;
224 }
225
226 PCEventMuxer::cb_ret_t PCEventMuxer::breakpointCallback(EventPtr ev) {
227         INITIAL_MUXING;
228
229     // Control transfer breakpoints are used for trap-based instrumentation
230     // No user interaction is required
231     EventBreakpoint::const_ptr evBreak = ev->getEventBreakpoint();
232
233     bool hasCtrlTransfer = false;
234     vector<Breakpoint::const_ptr> breakpoints;
235     evBreak->getBreakpoints(breakpoints);
236     Breakpoint::const_ptr ctrlTransferPt;
237     for(vector<Breakpoint::const_ptr>::iterator i = breakpoints.begin();
238             i != breakpoints.end(); ++i)
239     {
240         if( (*i)->isCtrlTransfer() ) {
241             hasCtrlTransfer = true;
242             ctrlTransferPt = *i;
243             break;
244         }
245
246         // Explicit synchronization unnecessary here
247         if( (*i) == process->getBreakpointAtMain() ) {
248             // We need to remove the breakpoint in the ProcControl callback to ensure
249             // the breakpoint is not automatically suspended and resumed
250             startup_printf("%s[%d]: removing breakpoint at main\n", FILE__, __LINE__);
251             if( !process->removeBreakpointAtMain() ) {
252                 proccontrol_printf("%s[%d]: failed to remove main breakpoint in event handling\n",
253                         FILE__, __LINE__);
254                 ev = Event::const_ptr(new Event(EventType::Error));
255             }
256
257             // If we are in the midst of bootstrapping, update the state to indicate
258             // that we have hit the breakpoint at main
259             if( !process->hasReachedBootstrapState(PCProcess::bs_readyToLoadRTLib) ) {
260                 process->setBootstrapState(PCProcess::bs_readyToLoadRTLib);
261             }
262
263             // Need to pass the event on the user thread to indicate to that the breakpoint
264             // at main was hit
265         }
266     }
267
268     if( hasCtrlTransfer ) {
269         proccontrol_printf("%s[%d]: received control transfer breakpoint on thread %d/%d (0x%lx => 0x%lx)\n",
270                 FILE__, __LINE__, ev->getProcess()->getPid(), ev->getThread()->getLWP(),
271                 evBreak->getAddress(), ctrlTransferPt->getToAddress());
272         ret = ret_continue;
273                 return ret;
274         }       
275
276         DEFAULT_RETURN;
277 }
278
279 PCEventMuxer::cb_ret_t PCEventMuxer::RPCCallback(EventPtr ev) {
280         INITIAL_MUXING;
281     EventRPC::const_ptr evRPC = ev->getEventRPC();
282     inferiorRPCinProgress *rpcInProg = static_cast<inferiorRPCinProgress *>(evRPC->getIRPC()->getData());
283
284     if( rpcInProg->resultRegister == REG_NULL ) {
285         // If the resultRegister isn't set, the returnValue shouldn't matter
286         rpcInProg->returnValue = NULL;
287     }else{
288         // Get the result out of a register
289         MachRegister resultReg = convertRegID(rpcInProg->resultRegister, 
290                 ev->getProcess()->getArchitecture());
291         MachRegisterVal resultVal;
292         if( !ev->getThread()->getRegister(resultReg, resultVal) ) {
293             proccontrol_printf("%s[%d]: failed to retrieve register from thread %d/%d\n",
294                     FILE__, __LINE__,
295                     ev->getProcess()->getPid(), ev->getThread()->getLWP());
296             ev = Event::const_ptr(new Event(EventType::Error));
297         }else{
298             rpcInProg->returnValue = (void *)resultVal;
299
300             proccontrol_printf("%s[%d]: iRPC %lu return value = 0x%lx\n",
301                 FILE__, __LINE__, rpcInProg->rpc->getID(),
302                 resultVal);
303         }
304     }
305
306         DEFAULT_RETURN;
307 }
308
309 PCEventMuxer::cb_ret_t PCEventMuxer::threadCreateCallback(EventPtr ev) {
310         INITIAL_MUXING;
311
312         ret = ret_default;
313
314         DEFAULT_RETURN;
315 }
316
317 void PCEventMuxer::enqueue(EventPtr ev) {
318         mailbox_.enqueue(ev);
319 }
320
321 PCEventMuxer::EventPtr PCEventMuxer::dequeue(bool block) {
322         return mailbox_.dequeue(block);
323 }
324
325
326 PCEventMailbox::PCEventMailbox()
327 {
328 }
329
330 PCEventMailbox::~PCEventMailbox()
331 {
332 }
333
334 void PCEventMailbox::enqueue(Event::const_ptr ev) {
335     queueCond.lock();
336     eventQueue.push(ev);
337     queueCond.broadcast();
338
339     proccontrol_printf("%s[%d]: Added event %s to mailbox\n", FILE__, __LINE__,
340             ev->name().c_str());
341
342     queueCond.unlock();
343 }
344
345 Event::const_ptr PCEventMailbox::dequeue(bool block) {
346     queueCond.lock();
347
348     if( eventQueue.empty() && !block ) {
349         queueCond.unlock();
350         return Event::const_ptr();
351     }
352
353     while( eventQueue.empty() ) {
354         proccontrol_printf("%s[%d]: Blocking for events from mailbox\n", FILE__, __LINE__);
355         queueCond.wait();
356     }
357
358     Event::const_ptr ret = eventQueue.front();
359     eventQueue.pop();
360     queueCond.unlock();
361
362     proccontrol_printf("%s[%d]: Returning event %s from mailbox\n", FILE__, __LINE__, ret->name().c_str());
363     return ret;
364 }
365
366 unsigned int PCEventMailbox::size() {
367     unsigned result = 0;
368     queueCond.lock();
369     result = (unsigned int) eventQueue.size();
370     queueCond.unlock();
371     return result;
372 }
373