2 * See the dyninst/COPYRIGHT file for copyright information.
4 * We provide the Paradyn Tools (below described as "Paradyn")
5 * on an AS IS basis, and do not warrant its validity or performance.
6 * We reserve the right to update, modify, or discontinue this
7 * software at any time. We shall have no obligation to supply such
8 * updates or modifications or any other form of support to you.
10 * By your use of Paradyn, you understand and agree that we (or any
11 * other person or entity with proprietary rights in Paradyn) are
12 * under no obligation to provide either maintenance services,
13 * update services, notices of latent defects, or correction of
14 * defects for Paradyn.
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
31 #include "dwarfFrameParser.h"
32 #include "dwarfExprParser.h"
33 #include "dwarfResult.h"
34 #include "VariableLocation.h"
39 #include "debug_common.h" // dwarf_printf
41 using namespace Dyninst;
42 using namespace Dwarf;
45 struct frameParser_key
49 frameParser_key(Dwarf_Debug d, Architecture a) : dbg(d), arch(a)
53 bool operator< (const frameParser_key& rhs) const
55 return (dbg < rhs.dbg) || (dbg == rhs.dbg && arch < rhs.arch);
62 std::map<DwarfFrameParser::frameParser_key, DwarfFrameParser::Ptr> DwarfFrameParser::frameParsers;
64 DwarfFrameParser::Ptr DwarfFrameParser::create(Dwarf_Debug dbg, Architecture arch) {
65 frameParser_key k(dbg, arch);
67 auto iter = frameParsers.find(k);
68 if (iter == frameParsers.end()) {
69 Ptr newParser = Ptr(new DwarfFrameParser(dbg, arch));
70 frameParsers[k] = newParser;
79 DwarfFrameParser::DwarfFrameParser(Dwarf_Debug dbg_, Architecture arch_) :
82 fde_dwarf_status(dwarf_status_uninitialized)
86 DwarfFrameParser::~DwarfFrameParser()
88 if (fde_dwarf_status != dwarf_status_ok)
90 for (unsigned i=0; i<fde_data.size(); i++)
92 dwarf_fde_cie_list_dealloc(dbg,
93 fde_data[i].cie_data, fde_data[i].cie_count,
94 fde_data[i].fde_data, fde_data[i].fde_count);
98 bool DwarfFrameParser::hasFrameDebugInfo()
101 return fde_dwarf_status == dwarf_status_ok;
104 bool DwarfFrameParser::getRegValueAtFrame(Address pc,
105 Dyninst::MachRegister reg,
106 Dyninst::MachRegisterVal ®_result,
107 ProcessReader *reader,
108 FrameErrors_t &err_result)
110 ConcreteDwarfResult cons(reader, arch, pc, dbg);
112 dwarf_printf("Getting concrete value for %s at 0x%lx\n",
113 reg.name().c_str(), pc);
114 if (!getRegAtFrame(pc, reg, cons, err_result)) {
115 assert(err_result != FE_No_Error);
116 dwarf_printf("\t Returning error from getRegValueAtFrame\n");
120 dwarf_printf("\t Computed dwarf result to an error\n");
121 err_result = FE_Frame_Eval_Error;
125 reg_result = cons.val();
126 dwarf_printf("Returning result 0x%lx for reg %s at 0x%lx\n",
127 reg_result, reg.name().c_str(), pc);
131 bool DwarfFrameParser::getRegRepAtFrame(Address pc,
132 Dyninst::MachRegister reg,
133 VariableLocation &loc,
134 FrameErrors_t &err_result) {
135 SymbolicDwarfResult cons(loc, arch);
137 dwarf_printf("Getting symbolic value for %s at 0x%lx\n",
138 reg.name().c_str(), pc);
139 if (!getRegAtFrame(pc, reg, cons, err_result)) {
140 dwarf_printf("\t Returning error from getRegRepAtFrame\n");
141 assert(err_result != FE_No_Error);
146 dwarf_printf("\t Computed dwarf result to an error\n");
147 err_result = FE_Frame_Eval_Error;
153 dwarf_printf("Returning symbolic result for reg %s at 0x%lx\n",
154 reg.name().c_str(), pc);
159 bool DwarfFrameParser::getRegsForFunction(Address entryPC,
160 Dyninst::MachRegister reg,
161 std::vector<VariableLocation> &locs,
162 FrameErrors_t &err_result) {
164 dwarf_printf("Entry to getRegsForFunction at 0x%lx, reg %s\n", entryPC, reg.name().c_str());
165 err_result = FE_No_Error;
168 * Initialize the FDE and CIE data. This is only really done once,
169 * after which setupFdeData will immediately return.
172 if (!fde_data.size()) {
173 err_result = FE_Bad_Frame_Data;
174 dwarf_printf("\t No FDE data, returning error\n");
179 * Get the FDE at this PC. The FDE contains the rules for getting
180 * registers at the given PC in this frame.
184 if (!getFDE(entryPC, fde, low, high, err_result)) {
185 dwarf_printf("\t Failed to find FDE for 0x%lx, returning error\n", entryPC);
186 assert(err_result != FE_No_Error);
190 dwarf_printf("\t Got FDE range 0x%lx..0x%lx\n", low, high);
192 Dwarf_Half dwarf_reg;
193 if (!getDwarfReg(reg, fde, dwarf_reg, err_result)) {
194 assert(err_result != FE_No_Error);
195 dwarf_printf("\t Failed to get dwarf register for %s\n", reg.name().c_str());
199 Address worker = high;
200 while (worker > low) {
201 dwarf_printf("\t Getting register representation for 0x%lx (reg %s)\n", worker, reg.name().c_str());
202 VariableLocation loc;
203 SymbolicDwarfResult cons(loc, arch);
205 if (!getRegAtFrame_aux(worker, fde, dwarf_reg, reg, cons, next, err_result)) {
206 assert(err_result != FE_No_Error);
207 dwarf_printf("\t Failed to get register representation, ret false\n");
214 locs.push_back(cons.val());
217 std::reverse(locs.begin(), locs.end());
221 bool DwarfFrameParser::getRegAtFrame(Address pc,
222 Dyninst::MachRegister reg,
224 FrameErrors_t &err_result) {
226 err_result = FE_No_Error;
228 dwarf_printf("getRegAtFrame for 0x%lx, %s\n", pc, reg.name().c_str());
230 * Initialize the FDE and CIE data. This is only really done once,
231 * after which setupFdeData will immediately return.
234 if (!fde_data.size()) {
235 dwarf_printf("\t No FDE data, ret false\n");
236 err_result = FE_Bad_Frame_Data;
241 * Get the FDE at this PC. The FDE contains the rules for getting
242 * registers at the given PC in this frame.
246 if (!getFDE(pc, fde, u1, u2, err_result)) {
247 dwarf_printf("\t No FDE at 0x%lx, ret false\n", pc);
248 assert(err_result != FE_No_Error);
252 Dwarf_Half dwarf_reg;
253 if (!getDwarfReg(reg, fde, dwarf_reg, err_result)) {
254 dwarf_printf("\t Failed to convert %s to dwarf reg, ret false\n",
256 assert(err_result != FE_No_Error);
261 return getRegAtFrame_aux(pc, fde, dwarf_reg, reg, cons, ignored, err_result);
264 bool DwarfFrameParser::getRegAtFrame_aux(Address pc,
266 Dwarf_Half dwarf_reg,
267 MachRegister orig_reg,
270 FrameErrors_t &err_result) {
274 int width = getArchAddressWidth(arch);
275 dwarf_printf("getRegAtFrame_aux for 0x%lx, addr width %d\n",
278 Dwarf_Small value_type;
279 Dwarf_Signed offset_relevant, register_num, offset_or_block_len;
284 * Decode the rule that describes how to get dwarf_reg at pc.
286 if (dwarf_reg != DW_FRAME_CFA_COL3) {
287 dwarf_printf("\tNot col3 reg, using default\n");
288 result = dwarf_get_fde_info_for_reg3(fde, dwarf_reg, pc, &value_type,
289 &offset_relevant, ®ister_num,
290 &offset_or_block_len,
291 &block_ptr, &row_pc, &err);
294 dwarf_printf("\tcol3 reg, using CFA\n");
295 result = dwarf_get_fde_info_for_cfa_reg3(fde, pc, &value_type,
296 &offset_relevant, ®ister_num,
297 &offset_or_block_len,
298 &block_ptr, &row_pc, &err);
300 if (result == DW_DLV_ERROR) {
301 err_result = FE_Bad_Frame_Data;
305 lowpc = (Address) row_pc;
306 dwarf_printf("\t Got FDE data starting at 0x%lx; value_type %d, offset_relevant %d, offset/block len %d\n",
307 lowpc, (int) value_type, (int) offset_relevant, offset_or_block_len);
310 * Interpret the rule and turn it into a real value.
313 if (value_type == DW_EXPR_OFFSET || value_type == DW_EXPR_VAL_OFFSET)
317 dwarf_printf("\tHandling returned FDE as expression\n");
318 if (!handleExpression(pc, register_num, orig_reg,
319 arch, cons, done, err_result)) {
320 dwarf_printf("\t Error handling expression, ret false\n");
321 assert(err_result != FE_No_Error);
325 dwarf_printf("\t Handled expression, indicated done, returning\n");
330 bool indirect = false;
333 // For a val offset, the value of the register is (other_reg + const)
334 case DW_EXPR_VAL_OFFSET:
336 dwarf_printf("\tHandling val_offset or offset\n");
337 if (offset_relevant) {
338 dwarf_printf("\t Offset relevant, adding %d\n", offset_or_block_len);
339 cons.pushSignedVal(offset_or_block_len);
340 cons.pushOp(DwarfResult::Add);
343 if (offset_relevant &&
344 dwarf_reg != DW_FRAME_CFA_COL3) {
345 dwarf_printf("\t Reg not CFA and offset relevant: indirect\n");
348 dwarf_printf("\t Done handling val_offset or offset\n");
350 case DW_EXPR_VAL_EXPRESSION:
351 case DW_EXPR_EXPRESSION: {
352 dwarf_printf("\t Handling val_expression or expression\n");
353 Dwarf_Locdesc *llbuf = NULL;
354 Dwarf_Signed listlen = 0;
355 result = dwarf_loclist_from_expr(dbg, block_ptr, offset_or_block_len, &llbuf, &listlen, &err);
356 if (result != DW_DLV_OK) {
357 dwarf_printf("\t Failed to get loclist, ret false\n");
358 err_result = FE_Frame_Read_Error;
362 if (!decodeDwarfExpression(llbuf, NULL,
365 dwarf_printf("\t Failed to decode dwarf expr, ret false\n");
366 err_result = FE_Frame_Eval_Error;
370 dwarf_dealloc(dbg, llbuf->ld_s, DW_DLA_LOC_BLOCK);
371 dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC);
373 if (value_type == DW_EXPR_EXPRESSION) {
374 dwarf_printf("\t Handling expression, adding indirect\n");
380 err_result = FE_Bad_Frame_Data;
385 dwarf_printf("\t Adding a dereference to handle \"address of\" operator\n");
386 cons.pushOp(DwarfResult::Deref, width);
392 void DwarfFrameParser::setupFdeData()
396 if (fde_dwarf_status == dwarf_status_ok ||
397 fde_dwarf_status == dwarf_status_error)
401 fde_dwarf_status = dwarf_status_error;
405 #if defined(dwarf_has_setframe)
406 dwarf_set_frame_cfa_value(dbg, DW_FRAME_CFA_COL3);
410 int result = dwarf_get_fde_list(dbg,
411 &fc.cie_data, &fc.cie_count,
412 &fc.fde_data, &fc.fde_count,
414 if (result == DW_DLV_OK) {
415 fde_data.push_back(fc);
418 result = dwarf_get_fde_list_eh(dbg,
419 &fc.cie_data, &fc.cie_count,
420 &fc.fde_data, &fc.fde_count,
422 if (result == DW_DLV_OK) {
423 fde_data.push_back(fc);
427 if (!fde_data.size()) {
428 fde_dwarf_status = dwarf_status_error;
431 fde_dwarf_status = dwarf_status_ok;
434 bool DwarfFrameParser::getFDE(Address pc, Dwarf_Fde &fde,
435 Address &low, Address &high,
436 FrameErrors_t &err_result) {
437 Dwarf_Addr lowpc = 0, hipc = 0;
438 dwarf_printf("Getting FDE for 0x%lx\n", pc);
441 for (cur_fde=0; cur_fde<fde_data.size(); cur_fde++) {
442 int result = dwarf_get_fde_at_pc(fde_data[cur_fde].fde_data,
443 (Dwarf_Addr) pc, &fde, &lowpc, &hipc, NULL);
444 if (result == DW_DLV_ERROR) {
445 dwarf_printf("\t Got ERROR return\n");
446 err_result = FE_Bad_Frame_Data;
449 else if (pc < lowpc || pc > hipc)
453 else if (result == DW_DLV_OK) {
454 dwarf_printf("\t Got range 0x%lx..0x%lx\n",
456 low = (Address) lowpc;
457 high = (Address) hipc;
464 dwarf_printf("\tEntry not found, ret false\n");
465 err_result = FE_No_Frame_Entry;
471 bool DwarfFrameParser::getDwarfReg(Dyninst::MachRegister reg,
473 Dwarf_Half &dwarf_reg,
474 FrameErrors_t &err_result) {
476 if (reg == Dyninst::ReturnAddr) {
478 * We should be getting the return address for the stack frame.
479 * This is treated as a virtual register in the
480 * FDE. We can look up the virtual register in the CIE.
483 int result = dwarf_get_cie_of_fde(fde, &cie, &err);
484 if (result != DW_DLV_OK) {
485 dwarf_printf("ARM-ERROR: bad return value.\n");
486 err_result = FE_Bad_Frame_Data;
490 Dwarf_Unsigned bytes_in_cie;
491 result = dwarf_get_cie_info(cie, &bytes_in_cie, NULL, NULL, NULL, NULL,
492 &dwarf_reg, NULL, NULL, &err);
493 if (result != DW_DLV_OK) {
494 dwarf_printf("ARM-ERROR: bad return value.\n");
495 err_result = FE_Bad_Frame_Data;
499 else if (reg == Dyninst::FrameBase || reg == Dyninst::CFA) {
500 dwarf_reg = DW_FRAME_CFA_COL3;
503 dwarf_reg = reg.getDwarfEnc();
508 bool DwarfFrameParser::handleExpression(Address pc,
509 Dwarf_Signed registerNum,
510 Dyninst::MachRegister origReg,
511 Dyninst::Architecture arch,
514 FrameErrors_t &err_result) {
515 dwarf_printf("HandleExpression\n");
518 dwarf_printf("register num %d\n", registerNum);
519 switch (registerNum) {
520 case DW_FRAME_CFA_COL3:
521 dwarf_printf("\t Getting frame base\n");
523 err_result = FE_No_Error;
524 if (!getRegAtFrame(pc, Dyninst::FrameBase,
526 assert(err_result != FE_No_Error);
530 case DW_FRAME_SAME_VAL:
531 dwarf_printf("\t Getting %s\n", origReg.name().c_str());
532 #if defined(arch_aarch64)
533 //if(origReg == Dyninst::ReturnAddr)
534 // origReg = Dyninst::aarch64::x30;
535 origReg = MachRegister::getArchRegFromAbstractReg(origReg, arch);
537 cons.readReg(origReg);
540 case DW_FRAME_UNDEFINED_VAL:
541 dwarf_printf("\t Value not available for %s\n", origReg.name().c_str());
542 err_result = FE_No_Frame_Entry;
546 Dyninst::MachRegister dyn_register = MachRegister::DwarfEncToReg(registerNum, arch);
547 dwarf_printf("\t Getting %s\n", dyn_register.name().c_str());
549 cons.readReg(dyn_register);