Build fixes for static linked Dyninst components (compute node linux), when linking...
[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
76 #define INLINE_ELF_X 
77 #include "common/src/Elf_X.C"
78
79 static DwarfSW *ll_getDwarfInfo(Elf_X *elfx)
80 {
81    Elf *elf = elfx->e_elfp();
82    Dwarf_Debug dbg;
83    Dwarf_Error err;
84    int status = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &err);
85    if (status != DW_DLV_OK) {
86       sw_printf("Error opening dwarf information %u (0x%x): %s\n",
87                 (unsigned) dwarf_errno(err), (unsigned) dwarf_errno(err),
88                 dwarf_errmsg(err));
89       return NULL;
90    }
91    return new DwarfSW(dbg, elfx->wordSize());
92 }
93
94 static DwarfSW *getDwarfInfo(std::string s)
95 {
96    static std::map<std::string, DwarfSW *> dwarf_info;
97
98    std::map<std::string, DwarfSW *>::iterator i = dwarf_info.find(s);
99    if (i != dwarf_info.end())
100       return i->second;
101
102    Elf_X *elfx = getElfHandle(s);
103    DwarfSW *result = ll_getDwarfInfo(elfx);
104    dwarf_info[s] = result;
105    return result;
106 }
107
108 static DwarfSW *getAuxDwarfInfo(std::string s)
109 {
110    static std::map<std::string, DwarfSW *> dwarf_aux_info;
111
112    std::map<std::string, DwarfSW *>::iterator i = dwarf_aux_info.find(s);
113    if (i != dwarf_aux_info.end())
114       return i->second;
115
116    Elf_X *orig_elf = getElfHandle(s);
117    if (!orig_elf) {
118       sw_printf("[%s:%u] - Error. Could not find elf handle for file %s\n",
119                 __FILE__, __LINE__, s.c_str());
120       dwarf_aux_info[s] = NULL;
121       return NULL;
122    }
123
124    string dbg_name;
125    char *dbg_buffer;
126    unsigned long dbg_buffer_size;
127    bool result = orig_elf->findDebugFile(s, dbg_name, dbg_buffer, dbg_buffer_size);
128    if (!result) {
129       sw_printf("[%s:%u] - No separate debug file associated with %s\n",
130                 __FILE__, __LINE__, s.c_str());
131       dwarf_aux_info[s] = NULL;
132       return NULL;
133    }
134    
135    SymbolReaderFactory *fact = getDefaultSymbolReader();
136    SymReader *reader = fact->openSymbolReader(dbg_buffer, dbg_buffer_size);
137    if (!reader) {
138       sw_printf("[%s:%u] - Error opening symbol reader for buffer associated with %s\n",
139                 __FILE__, __LINE__, dbg_name.c_str());
140       dwarf_aux_info[s] = NULL;
141       return NULL;
142    }
143
144    Elf_X *elfx = reader->getElfHandle();
145    DwarfSW *dresult = ll_getDwarfInfo(elfx);
146    dwarf_aux_info[s] = dresult;
147    return dresult;
148 }
149
150
151 DebugStepperImpl::DebugStepperImpl(Walker *w, DebugStepper *parent) :
152    FrameStepper(w),
153    parent_stepper(parent),
154    cur_frame(NULL),
155    last_addr_read(0),
156    last_val_read(0)
157 {
158 }
159
160 bool DebugStepperImpl::ReadMem(Address addr, void *buffer, unsigned size)
161 {
162    bool result = getProcessState()->readMem(buffer, addr, size);
163
164    last_addr_read = 0;
165    if (!result)
166       return false;
167    if (size != addr_width)
168       return true;
169    
170    last_addr_read = addr;
171    if (addr_width == 4) {
172       uint32_t v = *((uint32_t *) buffer);
173       last_val_read = v;
174    }
175    else if (addr_width == 8) {
176       uint64_t v = *((uint64_t *) buffer);
177       last_val_read = v;
178    }
179    else {
180       assert(0); //Unknown size
181    }
182
183    return true;
184 }
185
186 location_t DebugStepperImpl::getLastComputedLocation(unsigned long value)
187 {
188    location_t loc;
189    if (last_addr_read && last_val_read == value) {
190       loc.val.addr = last_addr_read;
191       loc.location = loc_address;
192    }
193    else {
194       loc.val.addr = 0;
195       loc.location = loc_unknown;
196    }
197    last_addr_read = 0;
198    last_val_read = 0;
199    return loc;
200 }
201
202 bool DebugStepperImpl::GetReg(MachRegister reg, MachRegisterVal &val)
203 {
204    if (reg.isFramePointer()) {
205       val = static_cast<MachRegisterVal>(cur_frame->getFP());
206       return true;
207    }
208
209    if (reg.isStackPointer()) {
210       val = static_cast<MachRegisterVal>(cur_frame->getSP());
211       return true;
212    }
213    
214    if (reg.isPC()) {
215       val = static_cast<MachRegisterVal>(cur_frame->getRA());
216       return true;
217    }
218
219    return false;
220 }
221
222 gcframe_ret_t DebugStepperImpl::getCallerFrame(const Frame &in, Frame &out)
223 {
224    LibAddrPair lib;
225    bool result;
226
227    result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(in.getRA(), lib);
228    if (!result) {
229       sw_printf("[%s:%u] - Stackwalking through an invalid PC at %lx\n",
230                 __FILE__, __LINE__, in.getRA());
231       return gcf_stackbottom;
232    }
233
234    Address pc = in.getRA() - lib.second;
235
236    /**
237     * Some system libraries on some systems have their debug info split
238     * into separate files, usually in /usr/lib/debug/.  Check these 
239     * for DWARF debug info
240     **/
241    DwarfSW *dauxinfo = getAuxDwarfInfo(lib.first);
242    if (dauxinfo && dauxinfo->hasFrameDebugInfo()) {
243       sw_printf("[%s:%u] - Using separate DWARF debug file for %s\n", 
244                 __FILE__, __LINE__, lib.first.c_str());
245       cur_frame = &in;
246       gcframe_ret_t gcresult = getCallerFrameArch(pc, in, out, dauxinfo);
247       cur_frame = NULL;
248       if (gcresult == gcf_success) {
249          sw_printf("[%s:%u] - Success walking with DWARF aux file\n",
250                    __FILE__, __LINE__);
251          return gcf_success;
252       }
253    }
254    
255    /**
256     * Check the actual file for DWARF stackwalking data
257     **/
258    DwarfSW *dinfo = getDwarfInfo(lib.first);
259    if (!dinfo) {
260       sw_printf("[%s:%u] - Could not open file %s for DWARF info\n",
261                 __FILE__, __LINE__, lib.first.c_str());
262       setLastError(err_nofile, "Could not open file for Debugging stackwalker\n");
263       return gcf_error;
264    }
265    if (!dinfo->hasFrameDebugInfo())
266    {
267       sw_printf("[%s:%u] - Library %s does not have stackwalking debug info\n",
268                  __FILE__, __LINE__, lib.first.c_str());
269       return gcf_not_me;
270    }   
271    cur_frame = &in;
272    gcframe_ret_t gcresult = getCallerFrameArch(pc, in, out, dinfo);
273    cur_frame = NULL;
274
275    return gcresult;
276 }
277
278 void DebugStepperImpl::registerStepperGroup(StepperGroup *group)
279 {
280    unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
281    if (addr_width == 4)
282       group->addStepper(parent_stepper, 0, 0xffffffff);
283 #if defined(arch_64bit)
284    else if (addr_width == 8)
285       group->addStepper(parent_stepper, 0, 0xffffffffffffffff);
286 #endif
287    else
288       assert(0 && "Unknown architecture word size");
289 }
290
291 unsigned DebugStepperImpl::getPriority() const
292 {
293    return debugstepper_priority;
294 }
295
296 DebugStepperImpl::~DebugStepperImpl()
297 {
298 }
299
300 #if defined(arch_x86) || defined(arch_x86_64)
301 gcframe_ret_t DebugStepperImpl::getCallerFrameArch(Address pc, const Frame &in, 
302                                                    Frame &out, DwarfSW *dinfo)
303 {
304    MachRegisterVal frame_value, stack_value, ret_value;
305    bool result;
306
307    Dyninst::Architecture arch;
308    addr_width = getProcessState()->getAddressWidth();
309    if (addr_width == 4)
310       arch = Dyninst::Arch_x86;
311    else
312       arch = Dyninst::Arch_x86_64;
313
314    result = dinfo->getRegValueAtFrame(pc, Dyninst::ReturnAddr,
315                                       ret_value, arch, this);
316    if (!result) {
317       sw_printf("[%s:%u] - Couldn't get return debug info at %lx\n",
318                 __FILE__, __LINE__, in.getRA());
319       return gcf_not_me;
320    }
321    location_t ra_loc = getLastComputedLocation(ret_value);
322    
323    Dyninst::MachRegister frame_reg;
324    if (addr_width == 4)
325       frame_reg = x86::ebp;
326    else
327       frame_reg = x86_64::rbp;
328
329    result = dinfo->getRegValueAtFrame(pc, frame_reg,
330                                       frame_value, arch, this);
331    if (!result) {
332       sw_printf("[%s:%u] - Couldn't get frame debug info at %lx\n",
333                  __FILE__, __LINE__, in.getRA());
334       return gcf_not_me;
335    }
336    location_t fp_loc = getLastComputedLocation(frame_value);
337
338    result = dinfo->getRegValueAtFrame(pc, Dyninst::FrameBase,
339                                       stack_value, arch, this);
340    if (!result) {
341       sw_printf("[%s:%u] - Couldn't get stack debug info at %lx\n",
342                  __FILE__, __LINE__, in.getRA());
343       return gcf_not_me;
344    }
345    location_t sp_loc = getLastComputedLocation(stack_value);
346
347    out.setRA(ret_value);
348    out.setFP(frame_value);
349    out.setSP(stack_value);
350    out.setRALocation(ra_loc);
351    out.setFPLocation(fp_loc);
352    out.setSPLocation(sp_loc);
353
354    return gcf_success;
355 }
356 #endif