Fix DwarfFrameParser, decodeDwarfExpression and DwarfResult
[dyninst.git] / dwarf / src / dwarfFrameParser.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  *
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.
9  *
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.
15  *
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.
20  *
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.
25  *
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
29  */
30 #include <typeinfo>
31 #include <string.h>
32 #include "dwarfFrameParser.h"
33 #include "dwarfExprParser.h"
34 #include "dwarfResult.h"
35 #include "VariableLocation.h"
36 #include "Types.h"
37 #include "elfutils/libdw.h"
38 #include <stdio.h>
39 #include <iostream>
40 #include "debug_common.h" // dwarf_printf
41 #include <libelf.h>
42
43 using namespace Dyninst;
44 using namespace DwarfDyninst;
45 using namespace std;
46
47
48 std::map<DwarfFrameParser::frameParser_key, DwarfFrameParser::Ptr> DwarfFrameParser::frameParsers;
49
50 DwarfFrameParser::Ptr DwarfFrameParser::create(Dwarf * dbg, Elf * eh_frame, Architecture arch)
51 {
52     if(!dbg && !eh_frame) return NULL;
53
54     frameParser_key k(dbg, eh_frame, arch);
55
56     auto iter = frameParsers.find(k);
57     if (iter == frameParsers.end()) {
58         Ptr newParser = Ptr(new DwarfFrameParser(dbg, eh_frame, arch));
59         frameParsers.insert(make_pair(k, newParser));
60         return newParser;
61     }
62     else {
63         return iter->second;
64     }
65 }
66
67
68 DwarfFrameParser::DwarfFrameParser(Dwarf * dbg_, Elf * eh_frame, Architecture arch_) :
69     dbg(dbg_),
70     dbg_eh_frame(eh_frame),
71     arch(arch_),
72     fde_dwarf_status(dwarf_status_uninitialized)
73 {
74 }
75
76 DwarfFrameParser::~DwarfFrameParser()
77 {
78     if (fde_dwarf_status != dwarf_status_ok)
79         return;
80     for (unsigned i=0; i<cfi_data.size(); i++)
81     {
82         // FIXME only do this for dwarf_getcfi_elf!
83         // // dwarf_cfi_end(cfi_data[i]);
84         //
85         // previous code
86         //dwarf_fde_cie_list_dealloc(dbg,
87         //        cfi_data[i].cfi_data, cfi_data[i].cie_count,
88         //        cfi_data[i].cfi_data, cfi_data[i].fde_count);
89     }
90 }
91
92 bool DwarfFrameParser::hasFrameDebugInfo()
93 {
94     setupCFIData();
95     return fde_dwarf_status == dwarf_status_ok;
96 }
97
98 bool DwarfFrameParser::getRegValueAtFrame(
99         Address pc,
100         Dyninst::MachRegister reg,
101         Dyninst::MachRegisterVal &reg_result,
102         ProcessReader *reader,
103         FrameErrors_t &err_result)
104 {
105     ConcreteDwarfResult cons(reader, arch, pc, dbg, dbg_eh_frame);
106
107     dwarf_printf("Getting concrete value for %s at 0x%lx\n",
108             reg.name().c_str(), pc);
109     if (!getRegAtFrame(pc, reg, cons, err_result)) {
110         assert(err_result != FE_No_Error);
111         dwarf_printf("\t Returning error from getRegValueAtFrame: %d\n", err_result);
112         return false;
113     }
114     if (cons.err()) {
115         dwarf_printf("\t Computed dwarf result to an error\n");
116         err_result = FE_Frame_Eval_Error;
117         return false;
118     }
119
120     reg_result = cons.val();
121     dwarf_printf("Returning result 0x%lx for reg %s at 0x%lx\n",
122             reg_result, reg.name().c_str(), pc);
123     return true;
124 }
125
126 bool DwarfFrameParser::getRegRepAtFrame(
127         Address pc,
128         Dyninst::MachRegister reg,
129         VariableLocation &loc,
130         FrameErrors_t &err_result)
131 {
132     SymbolicDwarfResult cons(loc, arch);
133
134     dwarf_printf("Getting symbolic value for %s at 0x%lx\n",
135             reg.name().c_str(), pc);
136     if (!getRegAtFrame(pc, reg, cons, err_result)) {
137         dwarf_printf("\t Returning error from getRegRepAtFrame\n");
138         assert(err_result != FE_No_Error);
139         return false;
140     }
141
142     if (cons.err()) {
143         dwarf_printf("\t Computed dwarf result to an error\n");
144         err_result = FE_Frame_Eval_Error;
145         return false;
146     }
147
148     loc = cons.val();
149
150     dwarf_printf("Returning symbolic result for reg %s at 0x%lx\n",
151             reg.name().c_str(), pc);
152
153     return true;
154 }
155
156 bool DwarfFrameParser::getRegsForFunction(
157         std::pair<Address, Address> range,
158         Dyninst::MachRegister reg,
159         std::vector<VariableLocation> &locs,
160         FrameErrors_t &err_result)
161 {
162     locs.clear();
163     dwarf_printf("Entry to getRegsForFunction at 0x%lx, range end 0x%lx, reg %s\n", range.first, range.second, reg.name().c_str());
164     err_result = FE_No_Error;
165
166     /**
167      * Initialize the FDE and CIE data.  This is only really done once,
168      * after which setupCFIData will immediately return.
169      **/
170     setupCFIData();
171     if (!cfi_data.size()) {
172         dwarf_printf("\t No FDE data, ret false\n");
173         err_result = FE_Bad_Frame_Data;
174         return false;
175     }
176
177     for(size_t i=0; i<cfi_data.size(); i++)
178     {
179         auto next_pc = range.first;
180         while(next_pc < range.second)
181         {
182             Dwarf_Frame * frame = NULL;
183             int result = dwarf_cfi_addrframe(cfi_data[i], next_pc, &frame);
184             if(result==-1) break;
185
186             Dwarf_Addr start_pc, end_pc;
187             dwarf_frame_info(frame, &start_pc, &end_pc, NULL);
188
189             Dwarf_Op * ops;
190             size_t nops;
191             result = dwarf_frame_cfa(frame, &ops, &nops);
192             if (result != 0) break;
193
194             VariableLocation loc2;
195             DwarfDyninst::SymbolicDwarfResult cons(loc2, arch);
196             if (!DwarfDyninst::decodeDwarfExpression(ops, nops, NULL, cons, arch)) break;
197             loc2.lowPC = next_pc;
198             loc2.hiPC = end_pc;
199
200             locs.push_back(cons.val());
201             next_pc = end_pc;
202         }
203     }
204
205     return !locs.empty();
206 }
207
208 bool DwarfFrameParser::getRegAtFrame(
209         Address pc,
210         Dyninst::MachRegister reg,
211         DwarfResult &cons,
212         FrameErrors_t &err_result)
213 {
214
215     err_result = FE_No_Error;
216
217     dwarf_printf("getRegAtFrame for 0x%lx, %s\n", pc, reg.name().c_str());
218
219     /**
220      * Initialize the FDE and CIE data.  This is only really done once,
221      * after which setupCFIData will immediately return.
222      **/
223     setupCFIData();
224     if (!cfi_data.size()) {
225         dwarf_printf("\t No FDE data, ret false\n");
226         err_result = FE_Bad_Frame_Data;
227         return false;
228     }
229
230     int not_found = 0; // if not found FDE covering PC, increment
231
232     // this for goes for each cfi_data to look for the frame at pc
233     // the first one it finds, use it and break out of the for
234     for(size_t i=0; i<cfi_data.size(); i++)
235     {
236         Dwarf_Frame * frame = NULL;
237         int result = dwarf_cfi_addrframe(cfi_data[i], pc, &frame);
238         if (result != 0) // 0 is success, not found FDE covering PC is returned -1
239         {
240             not_found++; //there can be 2 not found since cfi_data can have side 2
241             continue;
242         }
243
244         dwarf_printf("Found frame info in cfi_data[%zu], cfi_data.size=%zu \n", i, cfi_data.size());
245
246         // FDE found so make not_found=0 (FALSE), in case it was true because
247         // a previous loop
248         not_found=0;
249
250         // user can request CFA (same as FrameBase), ReturnAddr, or any register
251         // use dwarf_frame_info to get the register number for ReturnAddr
252         Dwarf_Addr start_pc, end_pc;
253         int dwarf_reg = dwarf_frame_info(frame, &start_pc, &end_pc, NULL);
254         if (reg != Dyninst::ReturnAddr &&
255                 reg != Dyninst::FrameBase &&
256                 reg != Dyninst::CFA )
257             dwarf_reg = reg.getDwarfEnc();
258
259         // now get the rule for the register reg
260         // if its CFA (same as FrameBase) use dwarf_frame_cfa
261         // else use dwarf_frame_register
262         Dwarf_Op * ops;
263         size_t nops;
264         if (reg == Dyninst::FrameBase || reg == Dyninst::CFA)
265         {
266             dwarf_printf("\t reg is FrameBase(CFA)\n");
267
268             result = dwarf_frame_cfa(frame, &ops, &nops);
269             if (result != 0 || nops == 0)
270             {
271                 err_result = FE_Frame_Read_Error;
272                 return false;
273             }
274             dwarf_printf("\t\t nops=%zu\n",nops);
275
276             if (!DwarfDyninst::decodeDwarfExpression(ops, nops, NULL, cons, arch)) {
277                 err_result = FE_Frame_Eval_Error;
278                 dwarf_printf("\t Failed to decode dwarf expr, ret false\n");
279                 return false;
280             }
281             return true;
282         }
283         else // get location description for dwarf_reg (which can be RA or reg(n))
284         {
285             dwarf_printf("\t parameter reg is %s\n", reg.name().c_str());
286             dwarf_printf("\t dwarf_reg (or column in CFI table) is %d\n", dwarf_reg);
287
288             Dwarf_Op ops_mem[3];
289             result = dwarf_frame_register (frame, dwarf_reg, ops_mem, &ops, &nops);
290
291             if (result != 0)
292             {
293                 err_result = FE_Frame_Read_Error;
294                 return false;
295             }
296
297             // case of undefined
298             if(nops == 0 && ops == ops_mem)
299             {
300                 dwarf_printf("\t case of undefined rule, treats as same_value\n");
301 #if defined(arch_aarch64)
302                 reg = MachRegister::getArchRegFromAbstractReg(reg, arch);
303                 dwarf_printf("\t aarch64 converted register reg=%s\n", reg.name().c_str());
304 #endif
305                 // Dyninst treats as same_value ???
306                 cons.readReg(reg);
307                 return true; // true because undefined is a valid output
308             }
309
310             // case of same_value
311             if(nops == 0 && ops == NULL)
312             {
313                 dwarf_printf("\t case of same_value rule\n");
314 #if defined(arch_aarch64)
315                 reg = MachRegister::getArchRegFromAbstractReg(reg, arch);
316                 dwarf_printf("\t aarch64 converted register reg=%s\n", reg.name().c_str());
317 #endif
318                 cons.readReg(reg);
319                 return true;
320             }
321
322             // translate dwarf reg to machine reg
323             //Dyninst::MachRegister dyn_register = MachRegister::DwarfEncToReg(dwarf_reg, arch);
324             //cons.readReg(dyn_register);
325
326             ConcreteDwarfResult aux_cdr;
327             // if is concrete, add Deref as last operation if there isn't DW_OP_stack_value
328             if(typeid(cons)==typeid(aux_cdr))
329             {
330                 // if last operation is not DW_OP_stack_value
331                 if(ops[nops-1].atom != DW_OP_stack_value)
332                 {
333                     // add DW_OP_deref
334                     Dwarf_Op * newOps = new Dwarf_Op[nops+1];
335                     memcpy(newOps, ops, nops * sizeof(Dwarf_Op));
336                     ops = newOps;
337                     ops[nops] = {DW_OP_deref, 0, 0, 0};
338                     nops++;
339                 }
340             }
341
342             // decode location description, rule dependes on some register
343             if (!DwarfDyninst::decodeDwarfExpression(ops, nops, NULL, cons, arch)) {
344                 err_result = FE_Frame_Eval_Error;
345                 dwarf_printf("\t Failed to decode dwarf expr, ret false\n");
346                 return false;
347             }
348
349             // Check if cons is Concrete, because there's no need to
350             // search CFA again
351             if(typeid(cons)==typeid(aux_cdr)) return true;
352
353             // From here cons is SymbolicDwarfResult
354
355             // check case of *ops = {DW_OP_call_frame_cfa, DW_OP_stack_value}
356             // this case would produce wrong frameoffset. The correct value
357             // of reg should be getting the CFA at the beginning of the FDE range
358             // and not at pc. So if this is the case, ignore the subsequent call
359             // to getRegAtFrame(pc, CFA).
360             if(nops==2)
361                 if(ops[0].atom==DW_OP_call_frame_cfa &&
362                         ops[1].atom== DW_OP_stack_value)
363                 {
364                     auto sdr = dynamic_cast<SymbolicDwarfResult &>(cons);
365                     VariableLocation& loc = sdr.val();
366                     if(loc.mr_reg == Dyninst::CFA) loc.mr_reg = reg;
367                     return true;
368                 }
369
370             // CFA (or FrameBase) is always associated ???
371             // usar outro cons
372             if (!getRegAtFrame(pc, Dyninst::CFA, cons, err_result)) {
373                 assert(err_result != FE_No_Error);
374                 return false;
375             }
376
377             return true;
378         }
379
380         break; // if found in the first cfi_data, no need to check in the second
381     }
382
383     if(not_found){
384         err_result = FE_No_Frame_Entry;
385         return false;
386     }
387
388     return true;
389
390 }
391
392 void DwarfFrameParser::setupCFIData()
393 {
394     if (fde_dwarf_status == dwarf_status_ok ||
395         fde_dwarf_status == dwarf_status_error)
396         return;
397
398     if (!dbg && !dbg_eh_frame) {
399         fde_dwarf_status = dwarf_status_error;
400         return;
401     }
402
403 #if defined(dwarf_has_setframe)
404     dwarf_set_frame_cfa_value(dbg, DW_FRAME_CFA_COL3);
405 #endif
406
407     Dwarf_CFI * cfi = nullptr;
408
409     // Try to get dwarf data from .debug_frame
410     cfi = dwarf_getcfi(dbg);
411     if (dbg && cfi)
412     {
413         cfi_data.push_back(cfi);
414     }
415
416     // Try to get dwarf data from .eh_frame
417     cfi = nullptr;
418     cfi = dwarf_getcfi_elf(dbg_eh_frame);
419     if (dbg_eh_frame && cfi)
420     {
421         cfi_data.push_back(cfi);
422     }
423
424     // Verify if it got any dwarf data
425     if (!cfi_data.size()) {
426         fde_dwarf_status = dwarf_status_error;
427     }
428     else{
429         fde_dwarf_status = dwarf_status_ok;
430     }
431 }
432