Collected Windows fixes
[dyninst.git] / stackwalk / src / frame.C
1 /*
2  * Copyright (c) 1996-2011 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/frame.h"
33 #include "stackwalk/h/walker.h"
34 #include "stackwalk/h/swk_errors.h"
35 #include "stackwalk/h/symlookup.h"
36 #include "stackwalk/h/procstate.h"
37
38 #include "stackwalk/src/symtab-swk.h"
39
40 #include <assert.h>
41 #include <string>
42
43 using namespace std;
44 using namespace Dyninst;
45 using namespace Dyninst::Stackwalker;
46
47 Frame::Frame() :
48   ra(0x0),
49   fp(0x0),
50   sp(0x0),
51   sym_value(NULL),
52   name_val_set(nv_unset),
53   top_frame(false),
54   bottom_frame(false),
55   frame_complete(false),
56   prev_frame(NULL),
57   stepper(NULL),
58   next_stepper(NULL),
59   walker(NULL),
60   originating_thread(NULL_THR_ID)
61 {
62   ra_loc.location = loc_unknown;
63   ra_loc.val.addr = 0x0;
64   fp_loc.location = loc_unknown;
65   fp_loc.val.addr = 0x0;
66   sp_loc.location = loc_unknown;
67   sp_loc.val.addr = 0x0;
68   
69   sw_printf("[%s:%u] - Created null frame at %p\n", __FILE__, __LINE__, this);
70 }
71
72 Frame::Frame(Walker *parent_walker) :
73   ra(0x0),
74   fp(0x0),
75   sp(0x0),
76   sym_value(NULL),
77   name_val_set(nv_unset),
78   top_frame(false),
79   bottom_frame(false),
80   frame_complete(false),
81   prev_frame(NULL),
82   stepper(NULL),
83   next_stepper(NULL),
84   walker(parent_walker),
85   originating_thread(NULL_THR_ID)
86 {
87   assert(walker);
88   ra_loc.location = loc_unknown;
89   ra_loc.val.addr = 0x0;
90   fp_loc.location = loc_unknown;
91   fp_loc.val.addr = 0x0;
92   sp_loc.location = loc_unknown;
93   sp_loc.val.addr = 0x0;
94   
95   sw_printf("[%s:%u] - Created frame at %p\n", __FILE__, __LINE__, this);
96 }
97
98 Frame *Frame::newFrame(Dyninst::MachRegisterVal pc, Dyninst::MachRegisterVal sp, Dyninst::MachRegisterVal fp, Walker *walker) {
99   sw_printf("[%s:%u] - Manually creating frame with %lx, %lx, %lx, %p\n",
100             __FILE__, __LINE__, pc, sp, fp, walker);
101   if (!walker) {
102     sw_printf("[%s:%u] - Trying to create Frame with NULL Walker\n",
103               __FILE__, __LINE__);
104     setLastError(err_badparam, "Walker parameter cannot be NULL when creating frame");
105   }
106   
107   Frame *newframe = new Frame(walker);
108   
109   newframe->setRA(pc);
110   newframe->setSP(sp);
111   newframe->setFP(fp);
112   
113   return newframe;
114 }
115
116 bool Frame::operator==(const Frame &F) const
117 {
118   return ((ra == F.ra) &&
119           (fp == F.fp) &&
120           (sp == F.sp) &&
121           (ra_loc == F.ra_loc) &&
122           (fp_loc == F.fp_loc) &&
123           (sp_loc == F.sp_loc) &&
124           (sym_name == F.sym_name) &&
125           (frame_complete == F.frame_complete) &&
126           (stepper == F.stepper) &&
127           (walker == F.walker) &&
128           (originating_thread == F.originating_thread));
129 }
130
131 void Frame::setStepper(FrameStepper *newstep) {
132   sw_printf("[%s:%u] - Setting frame %p's stepper to %p\n", 
133             __FILE__, __LINE__, this, newstep);
134   stepper = newstep;
135 }
136
137 void Frame::markTopFrame() {
138   sw_printf("[%s:%u] - Marking frame %p as top\n",
139             __FILE__, __LINE__, this);
140   top_frame = true;
141 }
142
143 void Frame::markBottomFrame() {
144   sw_printf("[%s:%u] - Marking frame %p as bottom\n", 
145             __FILE__, __LINE__, this);
146   bottom_frame = true;
147 }
148
149 Dyninst::MachRegisterVal Frame::getRA() const {
150   return ra;
151 }
152
153 Dyninst::MachRegisterVal Frame::getSP() const {
154   return sp;
155 }
156
157 Dyninst::MachRegisterVal Frame::getFP() const {
158   return fp;
159 }
160
161 location_t Frame::getRALocation() const {
162   return ra_loc;
163 }
164
165 location_t Frame::getSPLocation() const {
166   return sp_loc;
167 }
168
169 location_t Frame::getFPLocation() const {
170   return fp_loc;
171 }
172
173 void Frame::setRA(Dyninst::MachRegisterVal newval) {
174   sw_printf("[%s:%u] - Setting ra of frame %p to %lx\n",
175             __FILE__, __LINE__, this, newval);
176   ra = newval;
177   frame_complete = true;
178 }
179
180 void Frame::setFP(Dyninst::MachRegisterVal newval) {
181   sw_printf("[%s:%u] - Setting fp of frame %p to %lx\n",
182                           __FILE__, __LINE__, this, newval);
183   fp = newval;
184 }
185
186 void Frame::setSP(Dyninst::MachRegisterVal newval) {
187   sw_printf("[%s:%u] - Setting sp of frame %p to %lx\n",
188             __FILE__, __LINE__, this, newval);
189   sp = newval;
190 }
191
192 static void debug_print_location(const char *s, Frame *f, location_t val) {
193   if (val.location == loc_address)
194     sw_printf("[%s:%u] - Setting frame %p %s location to address %lx\n",
195               __FILE__, __LINE__, f, s, val.val.addr);
196   else if (val.location == loc_register)
197     sw_printf("[%s:%u] - Setting frame %p %s location to register %s\n",
198               __FILE__, __LINE__, f, s, val.val.reg.name().c_str());
199   else if (val.location == loc_unknown)
200      sw_printf("[%s:%u] - Setting frame %p %s location to unknown\n",
201                __FILE__, __LINE__, f, s);
202 }
203
204 void Frame::setRALocation(location_t newval) {
205   if (dyn_debug_stackwalk) {
206     debug_print_location("RA", this, newval);
207   }
208   ra_loc = newval;
209 }
210
211 void Frame::setSPLocation(location_t newval) {
212   if (dyn_debug_stackwalk) {
213     debug_print_location("SP", this, newval);
214   }
215   sp_loc = newval;
216 }
217
218 void Frame::setFPLocation(location_t newval) {
219   if (dyn_debug_stackwalk) {
220     debug_print_location("FP", this, newval);
221   }
222   fp_loc = newval;
223 }
224
225 void Frame::setNameValue() const {
226   if (name_val_set == nv_set || name_val_set == nv_err)
227     return;
228   
229   if (!walker) {
230     setLastError(err_nosymlookup, "No Walker object was associated with this frame");
231     sw_printf("[%s:%u] - Error, No walker found.\n", __FILE__, __LINE__);
232     name_val_set = nv_err;
233     return;
234   }
235   
236   SymbolLookup *lookup = walker->getSymbolLookup();
237   if (!lookup) {
238     setLastError(err_nosymlookup, "No SymbolLookup object was associated with the Walker");
239     sw_printf("[%s:%u] - Error, No symbol lookup found.\n", __FILE__, __LINE__);
240     name_val_set = nv_err;
241     return;
242   }
243   
244   bool result = lookup->lookupAtAddr(getRA(), sym_name, sym_value);
245   if (!result) {
246     sw_printf("[%s:%u] - Error, returned by lookupAtAddr().\n", __FILE__, __LINE__);
247     name_val_set = nv_err;
248   }
249   
250   sw_printf("[%s:%u] - Successfully looked up symbol for frame %p\n",
251             __FILE__, __LINE__, this);
252   
253   name_val_set = nv_set;
254 }
255
256 bool Frame::getName(std::string &str) const {
257   setNameValue();
258   if (name_val_set == nv_set) {
259     str = sym_name;
260     sw_printf("[%s:%u] - Frame::getName (frame %p) returning %s\n",
261               __FILE__, __LINE__, this, str.c_str());
262     return true;
263   }
264   else {
265     sw_printf("[%s:%u] - Frame::getName (frame %p) returning error\n",
266               __FILE__, __LINE__, this);
267     return false;
268   }
269 }
270
271 bool Frame::getObject(void* &obj) const {
272   setNameValue();
273   if (name_val_set == nv_set) {
274     obj = sym_value;
275     sw_printf("[%s:%u] - Frame::getObject (frame %p) returning %p\n",
276               __FILE__, __LINE__, this, obj);
277     return true;
278   }
279   else {
280     sw_printf("[%s:%u] - Frame::getObject (frame %p) returning error\n",
281               __FILE__, __LINE__, this);
282     return false;
283   }
284 }
285
286 bool Frame::isTopFrame() const {
287   return top_frame;
288 }
289
290 bool Frame::isBottomFrame() const {
291   return bottom_frame;
292 }
293
294 const Frame *Frame::getPrevFrame() const {
295   return prev_frame;
296 }
297
298 FrameStepper *Frame::getStepper() const {
299   return stepper;
300 }
301
302 FrameStepper *Frame::getNextStepper() const {
303   return next_stepper;
304 }
305
306 Walker *Frame::getWalker() const {
307   return walker;
308 }
309
310 bool Frame::isFrameComplete() const {
311   return frame_complete;
312 }
313
314 Frame::~Frame() {
315   sw_printf("[%s:%u] - Destroying frame %p\n", __FILE__, __LINE__, this);
316 }
317
318 #ifdef cap_stackwalker_use_symtab
319 bool Frame::getLibOffset(std::string &lib, Dyninst::Offset &offset, void*& symtab) const
320 #else
321 bool Frame::getLibOffset(std::string &lib, Dyninst::Offset &offset, void*&) const
322 #endif
323 {
324   LibraryState *libstate = getWalker()->getProcessState()->getLibraryTracker();
325   if (!libstate) {
326     sw_printf("[%s:%u] - getLibraryAtAddr, had no library tracker\n",
327               __FILE__, __LINE__);
328     setLastError(err_unsupported, "No valid library tracker registered");
329     return false;
330   }
331
332   LibAddrPair la;
333   bool result = libstate->getLibraryAtAddr(getRA(), la);
334   if (!result) {
335     sw_printf("[%s:%u] - getLibraryAtAddr returned false for %x\n",
336               __FILE__, __LINE__, getRA());
337     return false;
338   }
339
340   lib = la.first;
341   offset = getRA() - la.second;
342
343 #if defined(cap_stackwalker_use_symtab)
344   symtab = static_cast<void *>(SymtabWrapper::getSymtab(lib));
345 #endif
346
347   return true;
348 }
349
350 THR_ID Frame::getThread() const
351 {
352    return originating_thread;
353 }
354
355 void Frame::setThread(THR_ID t)
356 {
357    originating_thread = t;
358 }
359
360 FrameNode::FrameNode(frame_cmp_wrapper f) :
361    children(f),
362    parent(NULL),
363    walker(NULL),
364    had_error(false)
365 {
366 }
367
368 FrameNode::~FrameNode()
369 {
370 }
371
372 inline bool frame_cmp_wrapper::operator()(const FrameNode *a, const FrameNode *b) { 
373    if (a->frame_type == FrameNode::FTThread && b->frame_type == FrameNode::FTThread) {
374       Dyninst::PID a_pid = a->getWalker()->getProcessState()->getProcessId();
375       Dyninst::PID b_pid = b->getWalker()->getProcessState()->getProcessId();
376       if (a_pid != b_pid)
377          return a_pid < b_pid;
378       return a->thrd < b->thrd;
379    }
380    else if (a->frame_type == FrameNode::FTThread)
381       return false;
382    else if (b->frame_type == FrameNode::FTThread)
383       return true;
384    else
385       return f(a->frame, b->frame);
386 }
387
388 CallTree::CallTree(frame_cmp_t cmpf)
389 {
390    cmp_wrapper.f = cmpf;
391    head = new FrameNode(cmp_wrapper);
392    head->frame_type = FrameNode::FTHead;
393    head->parent = NULL;
394 }
395
396 static void deleteTree(FrameNode *node) {
397    frame_set_t &children = node->getChildren();
398    for (frame_set_t::iterator i = children.begin(); i != children.end(); i++)
399       deleteTree(*i);
400    delete(node);
401 }
402
403 CallTree::~CallTree() 
404 {
405    deleteTree(head);
406    head = NULL;
407 }
408
409 FrameNode *CallTree::addFrame(const Frame &f, FrameNode *parent)
410 {
411    FrameNode search_node(cmp_wrapper);
412    search_node.frame_type = FrameNode::FTFrame;
413    search_node.frame = f;
414
415    pair<frame_set_t::iterator, frame_set_t::iterator> is = parent->children.equal_range(&search_node);
416    bool found = (is.first != is.second);
417    if (found) {
418       //Common case, already have this node in tree, don't create a new one.
419       FrameNode *n = *is.first;
420       return n;
421    }
422
423    //Create and insert a new node at position i
424    FrameNode *new_node = new FrameNode(cmp_wrapper);
425    new_node->frame_type = FrameNode::FTFrame;
426    new_node->frame = f;
427    new_node->walker = f.getWalker();
428    parent->children.insert(is.first, new_node);
429
430    return new_node;
431 }
432
433 FrameNode *CallTree::addThread(THR_ID thrd, FrameNode *parent, Walker *walker, bool err_stack)
434 {
435    FrameNode *new_node = new FrameNode(cmp_wrapper);
436    assert(walker);
437    new_node->frame_type = FrameNode::FTThread;
438    new_node->thrd = thrd;
439    new_node->walker = walker;
440    new_node->had_error = err_stack;
441
442    pair<frame_set_t::iterator, bool> i = parent->children.insert(new_node);
443    if (!i.second) {
444       //Element already existed.
445       delete new_node;
446       return *(i.first);
447    }
448
449    return new_node;
450 }
451
452 void CallTree::addCallStack(const vector<Frame> &stk, THR_ID thrd, Walker *walker, bool err_stack)
453 {
454    FrameNode *cur = head;
455    for (vector<Frame>::const_reverse_iterator i = stk.rbegin(); i != stk.rend(); i++) {
456       cur = addFrame(*i, cur);
457    }
458    addThread(thrd, cur, walker, err_stack);
459 }
460  
461 bool Dyninst::Stackwalker::frame_addr_cmp(const Frame &a, const Frame &b)
462 {
463    return a.getRA() < b.getRA();
464 }
465
466 bool Dyninst::Stackwalker::frame_lib_offset_cmp(const Frame &a, const Frame &b)
467 {
468    string a_lib, b_lib;
469    Offset a_off = 0, b_off = 0;
470    void *a_ignore, *b_ignore;
471    a.getLibOffset(a_lib, a_off, a_ignore);
472    b.getLibOffset(b_lib, b_off, b_ignore);
473    int str_cmp = a_lib.compare(b_lib);
474    if (str_cmp < 0)
475       return true;
476    else if (str_cmp > 0)
477       return false;
478    else
479       return a_off < b_off;
480 }
481
482 bool Dyninst::Stackwalker::frame_symname_cmp(const Frame &a, const Frame &b)
483 {
484    string a_name, b_name;
485    a.getName(a_name);
486    b.getName(b_name);
487    return a_name < b_name;
488 }
489
490 bool Dyninst::Stackwalker::frame_lineno_cmp(const Frame &, const Frame &)
491 {
492    assert(0 && "frame_lineno_cmp unimplemented");
493         return false;
494 }