2 * Copyright (c) 1996-2011 Barton P. Miller
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.
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.
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.
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.
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
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"
44 using namespace Dyninst;
45 using namespace Stackwalker;
58 class VariableLocation {
61 storageRefClass refClass;
71 #define setSymtabError(x)
72 #define dwarf_printf sw_printf
73 #include "common/h/dwarfExpr.h"
74 #include "common/h/dwarfSW.h"
77 #include "common/src/Elf_X.C"
79 static DwarfSW *ll_getDwarfInfo(Elf_X *elfx)
81 Elf *elf = elfx->e_elfp();
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),
91 return new DwarfSW(dbg, elfx->wordSize());
94 static DwarfSW *getDwarfInfo(std::string s)
96 static std::map<std::string, DwarfSW *> dwarf_info;
98 std::map<std::string, DwarfSW *>::iterator i = dwarf_info.find(s);
99 if (i != dwarf_info.end())
102 Elf_X *elfx = getElfHandle(s);
103 DwarfSW *result = ll_getDwarfInfo(elfx);
104 dwarf_info[s] = result;
108 static DwarfSW *getAuxDwarfInfo(std::string s)
110 static std::map<std::string, DwarfSW *> dwarf_aux_info;
112 std::map<std::string, DwarfSW *>::iterator i = dwarf_aux_info.find(s);
113 if (i != dwarf_aux_info.end())
116 Elf_X *orig_elf = getElfHandle(s);
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;
126 unsigned long dbg_buffer_size;
127 bool result = orig_elf->findDebugFile(s, dbg_name, dbg_buffer, dbg_buffer_size);
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;
135 SymbolReaderFactory *fact = getDefaultSymbolReader();
136 SymReader *reader = fact->openSymbolReader(dbg_buffer, dbg_buffer_size);
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;
144 Elf_X *elfx = reader->getElfHandle();
145 DwarfSW *dresult = ll_getDwarfInfo(elfx);
146 dwarf_aux_info[s] = dresult;
151 DebugStepperImpl::DebugStepperImpl(Walker *w, DebugStepper *parent) :
153 parent_stepper(parent),
160 bool DebugStepperImpl::ReadMem(Address addr, void *buffer, unsigned size)
162 bool result = getProcessState()->readMem(buffer, addr, size);
167 if (size != addr_width)
170 last_addr_read = addr;
171 if (addr_width == 4) {
172 uint32_t v = *((uint32_t *) buffer);
175 else if (addr_width == 8) {
176 uint64_t v = *((uint64_t *) buffer);
180 assert(0); //Unknown size
186 location_t DebugStepperImpl::getLastComputedLocation(unsigned long value)
189 if (last_addr_read && last_val_read == value) {
190 loc.val.addr = last_addr_read;
191 loc.location = loc_address;
195 loc.location = loc_unknown;
202 bool DebugStepperImpl::GetReg(MachRegister reg, MachRegisterVal &val)
204 if (reg.isFramePointer()) {
205 val = static_cast<MachRegisterVal>(cur_frame->getFP());
209 if (reg.isStackPointer()) {
210 val = static_cast<MachRegisterVal>(cur_frame->getSP());
215 val = static_cast<MachRegisterVal>(cur_frame->getRA());
222 gcframe_ret_t DebugStepperImpl::getCallerFrame(const Frame &in, Frame &out)
227 result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(in.getRA(), lib);
229 sw_printf("[%s:%u] - Stackwalking through an invalid PC at %lx\n",
230 __FILE__, __LINE__, in.getRA());
231 return gcf_stackbottom;
234 Address pc = in.getRA() - lib.second;
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
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());
246 gcframe_ret_t gcresult = getCallerFrameArch(pc, in, out, dauxinfo);
248 if (gcresult == gcf_success) {
249 sw_printf("[%s:%u] - Success walking with DWARF aux file\n",
256 * Check the actual file for DWARF stackwalking data
258 DwarfSW *dinfo = getDwarfInfo(lib.first);
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");
265 if (!dinfo->hasFrameDebugInfo())
267 sw_printf("[%s:%u] - Library %s does not have stackwalking debug info\n",
268 __FILE__, __LINE__, lib.first.c_str());
272 gcframe_ret_t gcresult = getCallerFrameArch(pc, in, out, dinfo);
278 void DebugStepperImpl::registerStepperGroup(StepperGroup *group)
280 unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
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);
288 assert(0 && "Unknown architecture word size");
291 unsigned DebugStepperImpl::getPriority() const
293 return debugstepper_priority;
296 DebugStepperImpl::~DebugStepperImpl()
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)
304 MachRegisterVal frame_value, stack_value, ret_value;
307 Dyninst::Architecture arch;
308 addr_width = getProcessState()->getAddressWidth();
310 arch = Dyninst::Arch_x86;
312 arch = Dyninst::Arch_x86_64;
314 result = dinfo->getRegValueAtFrame(pc, Dyninst::ReturnAddr,
315 ret_value, arch, this);
317 sw_printf("[%s:%u] - Couldn't get return debug info at %lx\n",
318 __FILE__, __LINE__, in.getRA());
321 location_t ra_loc = getLastComputedLocation(ret_value);
323 Dyninst::MachRegister frame_reg;
325 frame_reg = x86::ebp;
327 frame_reg = x86_64::rbp;
329 result = dinfo->getRegValueAtFrame(pc, frame_reg,
330 frame_value, arch, this);
332 sw_printf("[%s:%u] - Couldn't get frame debug info at %lx\n",
333 __FILE__, __LINE__, in.getRA());
336 location_t fp_loc = getLastComputedLocation(frame_value);
338 result = dinfo->getRegValueAtFrame(pc, Dyninst::FrameBase,
339 stack_value, arch, this);
341 sw_printf("[%s:%u] - Couldn't get stack debug info at %lx\n",
342 __FILE__, __LINE__, in.getRA());
345 location_t sp_loc = getLastComputedLocation(stack_value);
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);