Initial commit of StackwalkerAPI
[dyninst.git] / stackwalk / src / procstate.C
1 /*
2  * Copyright (c) 1996-2007 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
32 #include "stackwalk/h/swk_errors.h"
33 #include "stackwalk/h/procstate.h"
34 #include "common/h/headers.h"
35 #include <assert.h>
36 #include <string>
37 #include <vector>
38
39 using namespace Dyninst;
40 using namespace Dyninst::Stackwalker;
41 using namespace std;
42
43 void ProcessState::preStackwalk()
44 {
45 }
46
47 void ProcessState::postStackwalk()
48 {
49 }
50
51 ProcessState::~ProcessState()
52 {
53 }
54
55 bool procdebug_ltint::operator()(int a, int b) const
56 {
57    return a < b;
58 }
59
60 std::map<PID, ProcDebug *, procdebug_ltint> ProcDebug::proc_map;
61 int ProcDebug::pipe_in = -1;
62 int ProcDebug::pipe_out = -1;
63
64 ProcDebug::ProcDebug(PID p) : 
65   state(ps_neonatal),
66   isRunning(false),
67   user_isRunning(false),
68   should_resume(false),
69   pid(p)
70 {
71    std::map<PID, ProcDebug *, procdebug_ltint>::iterator i = proc_map.find(p);
72    if (i != proc_map.end())
73    {
74       sw_printf("[%s:%u] - Already attached to debuggee %d\n",
75                 __FILE__, __LINE__, pid);
76       setLastError(err_badparam, "Attach requested to already " \
77                    "attached to process");
78       return;
79    }
80    
81    proc_map[pid] = this;
82 }
83
84 ProcDebug::ProcDebug(const std::string & /*executable*/, 
85                      const std::vector<std::string> & /*argv*/) : 
86   state(ps_neonatal),
87   isRunning(false),
88   user_isRunning(false),
89   should_resume(false)
90 {
91 }
92
93 bool ProcDebug::create(const string &executable, 
94                        const vector<string> &argv)
95 {
96   bool result = debug_create(executable, argv);
97   if (!result) {
98     sw_printf("[%s:%u] - Could not create debuggee, %s\n",
99               __FILE__, __LINE__, executable.c_str());
100     return false;
101   }
102
103   proc_map[pid] = this;
104
105   sw_printf("[%s:%u] - Created debugged %s on pid %d\n",
106             __FILE__, __LINE__, executable.c_str(), pid);
107   result = debug_waitfor_create();
108   if (state == ps_exited) {
109      sw_printf("[%s:%u] - Process %s exited during create\n", 
110                __FILE__, __LINE__, executable.c_str());
111     return false; 
112   }
113   if (!result) {
114     sw_printf("[%s:%u] - Error during process create for %s\n",
115               __FILE__, __LINE__, pid);
116     return false;
117   }
118   assert(state == ps_running);
119   
120   /*
121   if (!isRunning) {
122     result = resume();
123     if (!result) {
124       sw_printf("[%s:%u] - Could not continue process %d after create\n",
125                 __FILE__, __LINE__, pid);
126       return false;
127     }
128   }
129   */
130   
131   return true;
132 }
133
134 bool ProcDebug::debug_waitfor_create()
135 {
136   for (;;) {
137     bool handled, result;
138     
139     result = debug_wait_and_handle(true, handled);
140     if (!result || state == ps_errorstate) {
141       sw_printf("[%s:%u] - Error.  Process %d errored during create\n",
142                 __FILE__, __LINE__, pid);
143       return false;
144     }
145     if (state == ps_exited) {
146       sw_printf("[%s:%u] - Error.  Process %d exited during create\n",
147                 __FILE__, __LINE__, pid);
148       return false;
149     }
150     if (state == ps_running) {
151       sw_printf("[%s:%u] - Successfully completed create on %d\n",
152                 __FILE__, __LINE__, pid);
153       return true;
154     }
155   }
156 }
157
158 bool ProcDebug::multi_attach(vector<ProcDebug *> &pids)
159 {
160    bool result;
161    bool had_error = false;
162    vector<ProcDebug *>::iterator i;
163
164 #define for_each_procdebug(func, cond, err_msg) \
165    for (i = pids.begin(); i != pids.end(); i++) { \
166       ProcDebug *pd = (*i); \
167       if (!pd) \
168         continue; \
169       if (!cond) \
170         continue; \
171       result = pd->func(); \
172       if (!result) { \
173          sw_printf("[%s:%u] - Could not %s to %d", __FILE__, __LINE__, err_msg, pd->pid); \
174          delete pd; \
175          *i = NULL; \
176          had_error = true; \
177       } \
178    }
179
180    for_each_procdebug(debug_attach, true, "attach");
181
182    for_each_procdebug(debug_waitfor_attach, true, "wait for attach");
183
184    for_each_procdebug(debug_continue, (pd->state != ps_running), "send continue");
185
186    return had_error;
187 }
188
189 bool ProcDebug::attach()
190 {
191   bool result = debug_attach();
192   if (!result) {
193     sw_printf("[%s:%u] - Could not attach to debuggee, %d\n",
194               __FILE__, __LINE__, pid);
195     return false;
196   }
197
198   result = debug_waitfor_attach();
199   if (!result) {
200      sw_printf("[%s:%u] - Error waiting for attach\n", __FILE__, __LINE__);
201      goto error;
202   }
203
204   if (state != ps_running) {
205      result = debug_continue();
206      if (!result) {
207         sw_printf("[%s:%u] - Could not continue debuggee %d after attach\n",
208                   __FILE__, __LINE__, pid);
209         goto error;
210      }
211   }
212
213   assert(state == ps_running);
214   return true;
215
216  error:
217   if (state == ps_exited) {
218     setLastError(err_procexit, "Process exited unexpectedly during attach");
219   }
220   sw_printf("[%s:%u] - Error during process attach for %d\n",
221             __FILE__, __LINE__, pid);
222   return false;
223 }
224
225
226 bool ProcDebug::debug_waitfor_attach()
227 {
228   for (;;) {
229     bool handled, result;
230
231     if (state == ps_exited) {
232       sw_printf("[%s:%u] - Error.  Process %d exited during attach\n",
233                 __FILE__, __LINE__, pid);
234       return false;
235     }
236     if (state == ps_attached || state == ps_running)  {
237       sw_printf("[%s:%u] - Successfully completed attach on %d\n",
238                 __FILE__, __LINE__, pid);
239       return true;
240     }
241     
242     result = debug_wait_and_handle(true, handled);
243     if (!result || state == ps_errorstate) {
244       sw_printf("[%s:%u] - Error.  Process %d errored during attach\n",
245                 __FILE__, __LINE__, pid);
246       return false;
247     }
248   }
249 }
250
251 bool ProcDebug::resume()
252 {
253    bool result = debug_continue();
254    if (!result) {
255       sw_printf("[%s:%u] - Could not resume debugee %d\n",
256                 __FILE__, __LINE__, pid);
257       return false;
258    }
259
260    result = debug_waitfor_continue();
261    if (state == ps_exited) {
262       setLastError(err_procexit, "Process exited unexpectedly during continue");
263       return false; 
264    }
265    if (!result) {
266       sw_printf("[%s:%u] - Error during process resume for %d\n",
267                 __FILE__, __LINE__, pid);
268       return false;
269    }
270    
271    user_isRunning = true;
272
273    assert(isRunning);
274    return true;
275 }
276
277 bool ProcDebug::debug_waitfor_continue()
278 {
279   while (!isRunning) {
280     bool handled, result;
281     
282     result = debug_wait_and_handle(true, handled);
283     if (!result || state == ps_errorstate) {
284       sw_printf("[%s:%u] - Error.  Process %d errored during attach\n",
285                 __FILE__, __LINE__, pid);
286       return false;
287     }
288     if (state == ps_exited) {
289       sw_printf("[%s:%u] - Error.  Process %d exited during attach\n",
290                 __FILE__, __LINE__, pid);
291       return false;
292     }
293   }
294   sw_printf("[%s:%u] - Successfully continued %d\n",
295             __FILE__, __LINE__, pid);
296   return true;
297 }
298
299 bool ProcDebug::pause()
300 {
301   bool result = debug_pause();
302   if (!result) {
303     sw_printf("[%s:%u] - Could not pause debuggee %d\n",
304               __FILE__, __LINE__, pid);
305     return false;
306   }
307   
308   result = debug_waitfor_pause();
309   if (state == ps_exited) {
310     setLastError(err_procexit, "Process exited unexpectedly during pause");
311     return false; 
312   }
313   if (!result) {
314     sw_printf("[%s:%u] - Error during process pause for %d\n",
315               __FILE__, __LINE__, pid);
316     return false;
317   }
318
319   user_isRunning = false;
320
321   assert(!isRunning);
322   return true;
323 }
324
325 bool ProcDebug::debug_waitfor_pause()
326 {
327   sw_printf("[%s:%u] - Waiting for %d to stop\n", __FILE__, __LINE__, pid);
328   while (isRunning) {
329     bool handled, result;
330     
331     result = debug_wait_and_handle(true, handled);
332     if (!result || state == ps_errorstate) {
333       sw_printf("[%s:%u] - Error.  Process %d errored during pause\n",
334                 __FILE__, __LINE__, pid);
335       return false;
336     }
337     if (state == ps_exited) {
338       sw_printf("[%s:%u] - Error.  Process %d exited during pause\n",
339                 __FILE__, __LINE__, pid);
340       return false;
341     }
342   }
343   sw_printf("[%s:%u] - Successfully stopped %d\n", __FILE__, __LINE__, pid);
344   return true;
345 }
346
347 bool ProcDebug::debug_wait_and_handle(bool block, bool &handled)
348 {
349   bool result;
350   DebugEvent ev = debug_get_event(block);
351
352   if (ev.dbg == dbg_noevent)
353   {
354     sw_printf("[%s:%u] - Returning from debug_wait_and_handle with nothing to do\n",
355               __FILE__, __LINE__);
356     handled = false;
357     return true;
358   }
359   if (ev.dbg == dbg_err)
360   {
361     sw_printf("[%s:%u] - Returning from debug_wait_and_handle with error\n",
362               __FILE__, __LINE__);
363     handled = false;
364     return false;
365   }
366
367   sw_printf("[%s:%u] - Handling event on for pid %d: dbg %d, data %d\n", 
368             __FILE__, __LINE__, ev.proc->pid, ev.dbg, ev.data.idata);
369   result = ev.proc->debug_handle_event(ev);
370
371   if (!result) {
372     sw_printf("[%s:%u] - debug_handle_event returned error for ev.dbg = %d, " \
373               "ev.proc = %d\n", __FILE__, __LINE__, ev.dbg, ev.proc->pid);
374     handled = false;
375     return false;
376   }
377   
378   sw_printf("[%s:%u] - Event %d on pid %d successfully handled\n", 
379             __FILE__, __LINE__, ev.dbg, ev.proc->pid);
380   handled = true;
381   return true;
382
383
384 ProcDebug::~ProcDebug()
385 {
386 }
387
388 unsigned ProcSelf::getAddressWidth()
389 {
390    return sizeof(void *);
391 }
392
393 PID ProcSelf::getProcessId()
394 {
395   return mypid;
396 }
397
398 ProcSelf::~ProcSelf()
399 {
400 }
401
402 bool ProcDebug::handleDebugEvent(bool block)
403 {
404   bool result;
405   bool handled;
406   
407   result = debug_wait_and_handle(block, handled);
408   if (!result) {
409     sw_printf("[%s:%u] - Error waiting for event in handleDebugEvent\n",
410               __FILE__, __LINE__);
411     return false;
412   }
413
414   return true;
415 }
416
417 PID ProcDebug::getProcessId()
418 {
419    return pid;
420 }
421
422 void ProcDebug::preStackwalk()
423 {
424    if (isRunning) {
425       should_resume = true;
426       pause();
427    }
428 }
429
430 void ProcDebug::postStackwalk()
431 {
432    if (should_resume) {
433       resume();
434       should_resume = false;
435    }
436 }
437
438 bool ProcDebug::isTerminated()
439 {
440   return (state == ps_exited || state == ps_errorstate);
441 }
442