Move debuglink location processing from SymtabAPI to Elf_X, so that it's accessible...
[dyninst.git] / stackwalk / src / dbginfo-stepper.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/framestepper.h"
33 #include "stackwalk/h/frame.h"
34 #include "stackwalk/h/procstate.h"
35 #include "stackwalk/h/swk_errors.h"
36 #include "stackwalk/h/steppergroup.h"
37 #include "stackwalk/h/walker.h"
38 #include "stackwalk/src/dbgstepper-impl.h"
39 #include "stackwalk/src/linux-swk.h"
40 #include "stackwalk/src/libstate.h"
41 #include "dynutil/h/dyntypes.h"
42
43
44 using namespace Dyninst;
45 using namespace Stackwalker;
46
47 typedef enum {
48    storageAddr,
49    storageReg,
50    storageRegOffset
51 } storageClass;
52
53 typedef enum {
54    storageRef,
55    storageNoRef
56 } storageRefClass;
57
58 class VariableLocation {
59 public:
60    storageClass stClass;
61    storageRefClass refClass;
62    int reg;
63    MachRegister mr_reg;
64    long frameOffset;
65    Address lowPC;
66    Address hiPC;
67 };
68
69 #include "dwarf.h"
70 #include "libdwarf.h"
71 #define setSymtabError(x) 
72 #define dwarf_printf sw_printf
73 #include "common/h/dwarfExpr.h"
74 #include "common/h/dwarfSW.h"
75 #include "common/h/Elf_X.h"
76
77 static DwarfSW *ll_getDwarfInfo(Elf_X *elfx)
78 {
79    Elf *elf = elfx->e_elfp();
80    Dwarf_Debug dbg;
81    Dwarf_Error err;
82    int status = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &err);
83    if (status != DW_DLV_OK) {
84       sw_printf("Error opening dwarf information %u (0x%x): %s\n",
85                 (unsigned) dwarf_errno(err), (unsigned) dwarf_errno(err),
86                 dwarf_errmsg(err));
87       return NULL;
88    }
89    return new DwarfSW(dbg, elfx->wordSize());
90 }
91
92 static DwarfSW *getDwarfInfo(std::string s)
93 {
94    static std::map<std::string, DwarfSW *> dwarf_info;
95
96    std::map<std::string, DwarfSW *>::iterator i = dwarf_info.find(s);
97    if (i != dwarf_info.end())
98       return i->second;
99
100    Elf_X *elfx = getElfHandle(s);
101    DwarfSW *result = ll_getDwarfInfo(elfx);
102    dwarf_info[s] = result;
103    return result;
104 }
105
106 static DwarfSW *getAuxDwarfInfo(std::string s)
107 {
108    static std::map<std::string, DwarfSW *> dwarf_aux_info;
109
110    std::map<std::string, DwarfSW *>::iterator i = dwarf_aux_info.find(s);
111    if (i != dwarf_aux_info.end())
112       return i->second;
113
114    Elf_X *orig_elf = getElfHandle(s);
115    if (!orig_elf) {
116       sw_printf("[%s:%u] - Error. Could not find elf handle for file %s\n",
117                 __FILE__, __LINE__, s.c_str());
118       dwarf_aux_info[s] = NULL;
119       return NULL;
120    }
121
122    string dbg_name;
123    char *dbg_buffer;
124    unsigned long dbg_buffer_size;
125    bool result = orig_elf->findDebugFile(s, dbg_name, dbg_buffer, dbg_buffer_size);
126    if (!result) {
127       sw_printf("[%s:%u] - No separate debug file associated with %s\n",
128                 __FILE__, __LINE__, s.c_str());
129       dwarf_aux_info[s] = NULL;
130       return NULL;
131    }
132    
133    SymbolReaderFactory *fact = getDefaultSymbolReader();
134    SymReader *reader = fact->openSymbolReader(dbg_buffer, dbg_buffer_size);
135    if (!reader) {
136       sw_printf("[%s:%u] - Error opening symbol reader for buffer associated with %s\n",
137                 __FILE__, __LINE__, dbg_name.c_str());
138       dwarf_aux_info[s] = NULL;
139       return NULL;
140    }
141
142    Elf_X *elfx = reader->getElfHandle();
143    DwarfSW *dresult = ll_getDwarfInfo(elfx);
144    dwarf_aux_info[s] = dresult;
145    return dresult;
146 }
147
148
149 DebugStepperImpl::DebugStepperImpl(Walker *w, DebugStepper *parent) :
150    FrameStepper(w),
151    parent_stepper(parent),
152    cur_frame(NULL)
153 {
154 }
155
156 bool DebugStepperImpl::ReadMem(Address addr, void *buffer, unsigned size)
157 {
158    return getProcessState()->readMem(buffer, addr, size);
159 }
160
161 bool DebugStepperImpl::GetReg(MachRegister reg, MachRegisterVal &val)
162 {
163    if (reg.isFramePointer()) {
164       val = static_cast<MachRegisterVal>(cur_frame->getFP());
165       return true;
166    }
167
168    if (reg.isStackPointer()) {
169       val = static_cast<MachRegisterVal>(cur_frame->getSP());
170       return true;
171    }
172    
173    if (reg.isPC()) {
174       val = static_cast<MachRegisterVal>(cur_frame->getRA());
175       return true;
176    }
177
178    return false;
179 }
180
181 gcframe_ret_t DebugStepperImpl::getCallerFrame(const Frame &in, Frame &out)
182 {
183    LibAddrPair lib;
184    bool result;
185
186    result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(in.getRA(), lib);
187    if (!result) {
188       sw_printf("[%s:%u] - Stackwalking through an invalid PC at %lx\n",
189                 __FILE__, __LINE__, in.getRA());
190       return gcf_stackbottom;
191    }
192
193    Address pc = in.getRA() - lib.second;
194
195    /**
196     * Some system libraries on some systems have their debug info split
197     * into separate files, usually in /usr/lib/debug/.  Check these 
198     * for DWARF debug info
199     **/
200    DwarfSW *dauxinfo = getAuxDwarfInfo(lib.first);
201    if (dauxinfo && dauxinfo->hasFrameDebugInfo()) {
202       sw_printf("[%s:%u] - Using separate DWARF debug file for %s", 
203                 __FILE__, __LINE__, lib.first.c_str());
204       cur_frame = &in;
205       gcframe_ret_t gcresult = getCallerFrameArch(pc, in, out, dauxinfo);
206       cur_frame = NULL;
207       if (gcresult == gcf_success) {
208          sw_printf("[%s:%u] - Success walking with DWARF aux file\n",
209                    __FILE__, __LINE__);
210          return gcf_success;
211       }
212    }
213    
214    /**
215     * Check the actual file for DWARF stackwalking data
216     **/
217    DwarfSW *dinfo = getDwarfInfo(lib.first);
218    if (!dinfo) {
219       sw_printf("[%s:%u] - Could not open file %s for DWARF info\n",
220                 __FILE__, __LINE__, lib.first.c_str());
221       setLastError(err_nofile, "Could not open file for Debugging stackwalker\n");
222       return gcf_error;
223    }
224    if (!dinfo->hasFrameDebugInfo())
225    {
226       sw_printf("[%s:%u] - Library %s does not have stackwalking debug info\n",
227                  __FILE__, __LINE__, lib.first.c_str());
228       return gcf_not_me;
229    }   
230    cur_frame = &in;
231    gcframe_ret_t gcresult = getCallerFrameArch(pc, in, out, dinfo);
232    cur_frame = NULL;
233
234    return gcresult;
235 }
236
237 void DebugStepperImpl::registerStepperGroup(StepperGroup *group)
238 {
239    unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
240    if (addr_width == 4)
241       group->addStepper(parent_stepper, 0, 0xffffffff);
242 #if defined(arch_64bit)
243    else if (addr_width == 8)
244       group->addStepper(parent_stepper, 0, 0xffffffffffffffff);
245 #endif
246    else
247       assert(0 && "Unknown architecture word size");
248 }
249
250 unsigned DebugStepperImpl::getPriority() const
251 {
252    return debugstepper_priority;
253 }
254
255 DebugStepperImpl::~DebugStepperImpl()
256 {
257 }
258
259 #if defined(arch_x86) || defined(arch_x86_64)
260 gcframe_ret_t DebugStepperImpl::getCallerFrameArch(Address pc, const Frame &in, 
261                                                    Frame &out, DwarfSW *dinfo)
262 {
263    MachRegisterVal frame_value, stack_value, ret_value;
264    bool result;
265
266    Dyninst::Architecture arch;
267    unsigned addr_width = getProcessState()->getAddressWidth();
268    if (addr_width == 4)
269       arch = Dyninst::Arch_x86;
270    else
271       arch = Dyninst::Arch_x86_64;
272
273    result = dinfo->getRegValueAtFrame(pc, Dyninst::ReturnAddr,
274                                       ret_value, arch, this);
275    if (!result) {
276       sw_printf("[%s:%u] - Couldn't get return debug info at %lx\n",
277                 __FILE__, __LINE__, in.getRA());
278       return gcf_not_me;
279    }
280    
281    Dyninst::MachRegister frame_reg;
282    if (addr_width == 4)
283       frame_reg = x86::ebp;
284    else
285       frame_reg = x86_64::rbp;
286
287    result = dinfo->getRegValueAtFrame(pc, frame_reg,
288                                       frame_value, arch, this);
289    if (!result) {
290       sw_printf("[%s:%u] - Couldn't get frame debug info at %lx\n",
291                  __FILE__, __LINE__, in.getRA());
292       return gcf_not_me;
293    }
294
295    result = dinfo->getRegValueAtFrame(pc, Dyninst::FrameBase,
296                                       stack_value, arch, this);
297    if (!result) {
298       sw_printf("[%s:%u] - Couldn't get stack debug info at %lx\n",
299                  __FILE__, __LINE__, in.getRA());
300       return gcf_not_me;
301    }
302
303    out.setRA(ret_value);
304    out.setFP(frame_value);
305    out.setSP(stack_value);
306
307    return gcf_success;
308 }
309 #endif
310
311
312