Infrastructure for SW CallTrees and group operations
[dyninst.git] / stackwalk / src / analysis_stepper.C
1 /*
2  * Copyright (c) 1996-2009 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/src/analysis_stepper.h"
33 #include "symtabAPI/h/Symtab.h"
34 #include "dataflowAPI/h/stackanalysis.h"
35 #include "stackwalk/h/swk_errors.h"
36 #include "stackwalk/h/frame.h"
37
38 #include "parseAPI/h/CodeSource.h"
39 #include "parseAPI/h/CodeObject.h"
40
41 using namespace Dyninst;
42 using namespace Stackwalker;
43 using namespace ParseAPI;
44 using namespace SymtabAPI;
45 using namespace std;
46
47 std::map<string, CodeObject *> AnalysisStepperImpl::objs;
48 const AnalysisStepperImpl::height_pair_t AnalysisStepperImpl::err_height_pair;
49
50 AnalysisStepperImpl::AnalysisStepperImpl(Walker *w, AnalysisStepper *p) :
51    FrameStepper(w),
52    parent(p)
53 {
54 }
55
56 AnalysisStepperImpl::~AnalysisStepperImpl()
57 {
58 }
59
60 CodeSource *AnalysisStepperImpl::getCodeSource(std::string name)
61 {
62    Symtab *symtab = NULL;
63    bool result = Symtab::openFile(symtab, name);
64    if (!result) {
65       sw_printf("[%s:%u] - SymtabAPI failed to open file %s\n", __FILE__, __LINE__, 
66                 name.c_str());
67       return NULL;
68    }
69    SymtabCodeSource *cs = new SymtabCodeSource(symtab);
70    return static_cast<CodeSource *>(cs);
71 }
72
73 CodeObject *AnalysisStepperImpl::getCodeObject(string name)
74 {
75    map<string, CodeObject *>::iterator i = objs.find(name);
76    if (i != objs.end()) {
77       return i->second;
78    }
79    
80    CodeSource *code_source = getCodeSource(name);
81    if (!code_source)
82       return NULL;
83    CodeObject *code_object = new CodeObject(code_source);
84    objs[name] = code_object;
85
86    code_object->parse();
87    return code_object;
88 }
89
90 AnalysisStepperImpl::height_pair_t AnalysisStepperImpl::analyzeFunction(string name,
91                                                                         Offset off)
92 {
93    CodeObject *obj = getCodeObject(name);
94    if (!obj) {
95       return err_height_pair;
96    }
97
98    set<CodeRegion *> regions;
99    obj->cs()->findRegions(off, regions);
100    
101    if (regions.empty()) {
102       sw_printf("[%s:%u] - Could not find region at %lx\n", __FILE__, __LINE__, off);
103       return err_height_pair;
104    }
105    //We shouldn't be dealing with overlapping regions in a live process
106    assert(regions.size() == 1);
107    CodeRegion *region = *(regions.begin());
108    
109    set<ParseAPI::Function*> funcs;
110    obj->findFuncs(region, off, funcs);
111    if (funcs.empty()) {
112       sw_printf("[%s:%u] - Could not find function at offset %lx\n", __FILE__,
113                 __LINE__, off);
114       return err_height_pair;
115    }
116
117    //Since there is only one region, there is only one block with the offset
118    set<ParseAPI::Block*> blocks;
119    obj->findBlocks(region, off, blocks);
120    assert(blocks.size() == 1);
121    ParseAPI::Block *block = *(blocks.begin());
122
123    set<height_pair_t> heights;
124    for (set<ParseAPI::Function *>::iterator i = funcs.begin(); i != funcs.end(); i++)
125    {
126       StackAnalysis analysis(*i);
127       heights.insert(height_pair_t(analysis.findSP(block, off), analysis.findFP(block, off)));
128    }
129
130    sw_printf("[%s:%u] - Have %lu possible stack heights in %s at %lx:\n", __FILE__, __LINE__, heights.size(), name.c_str(), off);
131    for (set<height_pair_t>::iterator i = heights.begin(); 
132         i != heights.end(); i++)
133    {
134       sw_printf("\tsp = %s, fp = %s\n", i->first.format().c_str(), i->second.format().c_str());
135    }
136
137    //Return the first pair found, until we work out something more sensible
138    return *(heights.begin());
139 }
140
141 gcframe_ret_t AnalysisStepperImpl::getCallerFrame(const Frame &in, Frame &out)
142 {
143    // For now, do not walk frames created by the Dyninst stepper
144    // as the stack pointer may not be correct
145    if (dynamic_cast<DyninstDynamicStepper*>(in.getStepper()))
146    {
147      return gcf_not_me;
148    }
149
150    LibAddrPair libaddr;
151    LibraryState *ls = getProcessState()->getLibraryTracker();
152    if (!ls) {
153       sw_printf("[%s:%u] - Failed to get library tracker\n", __FILE__, __LINE__);
154       return gcf_not_me;
155    }
156
157    bool result = ls->getLibraryAtAddr(in.getRA(), libaddr);
158    if (!result) {
159       sw_printf("[%s:%u] - Failed to get library at %lx\n", __FILE__, __LINE__, in.getRA());
160       return gcf_not_me;
161    }
162    
163    string name = libaddr.first;
164    Offset offset = in.getRA() - libaddr.second;
165
166    height_pair_t height_pair = analyzeFunction(name, offset);
167    if (height_pair == err_height_pair) {
168       sw_printf("[%s:%u] - Analysis failed on %s at %lx\n", __FILE__, __LINE__, name.c_str(), offset);
169       return gcf_not_me;
170    }
171
172    return getCallerFrameArch(height_pair, in, out);
173 }
174
175 unsigned AnalysisStepperImpl::getPriority() const
176 {
177    return analysis_priority;
178 }
179
180