FreeBSD, code relocation, and dwarf parsing fixes
[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
31 #include "dwarf/h/dwarfFrameParser.h"
32 #include "dwarf/h/dwarfExprParser.h"
33 #include "dwarf/h/dwarfResult.h"
34 #include "dynutil/h/VariableLocation.h"
35 #include "common/h/Types.h"
36 #include "libdwarf.h"
37 #include <stdio.h>
38 #include <iostream>
39
40 using namespace Dyninst;
41 using namespace Dwarf;
42 using namespace std;
43
44 std::map<Dwarf_Debug, DwarfFrameParser::Ptr> DwarfFrameParser::frameParsers;
45
46 DwarfFrameParser::Ptr DwarfFrameParser::create(Dwarf_Debug dbg, Architecture arch) {
47    std::map<Dwarf_Debug, DwarfFrameParser::Ptr>::iterator iter = frameParsers.find(dbg);
48    if (iter == frameParsers.end()) {
49       Ptr newParser = Ptr(new DwarfFrameParser(dbg, arch));
50       frameParsers[dbg] = newParser;
51       return newParser;
52    }
53    else {
54       assert(iter->second->arch == arch);
55       return iter->second;
56    }
57 }
58
59
60 DwarfFrameParser::DwarfFrameParser(Dwarf_Debug dbg_, Architecture arch_) :
61    dbg(dbg_),
62    arch(arch_),
63    fde_dwarf_status(dwarf_status_uninitialized)
64 {
65 }
66
67 DwarfFrameParser::~DwarfFrameParser()
68 {
69    if (fde_dwarf_status != dwarf_status_ok) 
70       return;
71    for (unsigned i=0; i<fde_data.size(); i++)
72    {
73       dwarf_fde_cie_list_dealloc(dbg, 
74                                  fde_data[i].cie_data, fde_data[i].cie_count, 
75                                  fde_data[i].fde_data, fde_data[i].fde_count);
76    }
77 }
78
79 bool DwarfFrameParser::hasFrameDebugInfo()
80 {
81    setupFdeData();
82    return fde_dwarf_status == dwarf_status_ok;
83 }
84
85 bool DwarfFrameParser::getRegValueAtFrame(Address pc, 
86                                  Dyninst::MachRegister reg,
87                                  Dyninst::MachRegisterVal &reg_result,
88                                  ProcessReader *reader,
89                                  FrameErrors_t &err_result)
90 {
91    ConcreteDwarfResult cons(reader, arch, pc, dbg);
92
93    if (!getRegAtFrame(pc, reg, cons, err_result)) {
94      assert(err_result != FE_No_Error);
95      return false;
96    }
97    if (cons.err()) {
98      err_result = FE_Frame_Eval_Error;
99       return false;
100    }
101
102    reg_result = cons.val();
103
104    return true;
105 }
106
107 bool DwarfFrameParser::getRegRepAtFrame(Address pc,
108                                Dyninst::MachRegister reg,
109                                VariableLocation &loc,
110                                FrameErrors_t &err_result) {
111    SymbolicDwarfResult cons(loc, arch);
112
113    if (!getRegAtFrame(pc, reg, cons, err_result)) {
114      assert(err_result != FE_No_Error);
115      return false;
116    }
117    
118    if (cons.err()) {
119       err_result = FE_Frame_Eval_Error;
120       return false;
121    }
122
123    loc = cons.val();
124
125    return true;
126 }
127
128 bool DwarfFrameParser::getRegsForFunction(Address entryPC,
129                                           Dyninst::MachRegister reg,
130                                           std::vector<VariableLocation> &locs,
131                                           FrameErrors_t &err_result) {
132    locs.clear();
133
134    err_result = FE_No_Error;
135
136    /**
137     * Initialize the FDE and CIE data.  This is only really done once, 
138     * after which setupFdeData will immediately return.
139     **/
140    setupFdeData();
141    if (!fde_data.size()) {
142       err_result = FE_Bad_Frame_Data;
143       return false;
144    }
145
146    /**
147     * Get the FDE at this PC.  The FDE contains the rules for getting
148     * registers at the given PC in this frame.
149     **/
150    Dwarf_Fde fde;
151    Address low, high;
152    if (!getFDE(entryPC, fde, low, high, err_result)) {
153      assert(err_result != FE_No_Error);
154      return false;
155    }
156    
157    Dwarf_Half dwarf_reg;
158    if (!getDwarfReg(reg, fde, dwarf_reg, err_result)) {
159      assert(err_result != FE_No_Error);
160      return false;
161    }
162
163    Address worker = high;
164    while (worker > low) {
165       VariableLocation loc;
166       SymbolicDwarfResult cons(loc, arch);
167       Address next;
168       if (!getRegAtFrame_aux(worker, fde, dwarf_reg, reg, cons, next, err_result)) {
169         assert(err_result != FE_No_Error);
170          return false;
171       }
172       loc.lowPC = next;
173       loc.hiPC = worker;
174
175       worker = next - 1;
176       locs.push_back(cons.val());
177    }
178
179    std::reverse(locs.begin(), locs.end());
180    return true;
181 }
182
183 bool DwarfFrameParser::getRegAtFrame(Address pc,
184                                      Dyninst::MachRegister reg,
185                                      DwarfResult &cons,
186                                      FrameErrors_t &err_result) {
187
188    err_result = FE_No_Error;
189
190    /**
191     * Initialize the FDE and CIE data.  This is only really done once, 
192     * after which setupFdeData will immediately return.
193     **/
194    setupFdeData();
195    if (!fde_data.size()) {
196       err_result = FE_Bad_Frame_Data;
197       return false;
198    }
199
200    /**
201     * Get the FDE at this PC.  The FDE contains the rules for getting
202     * registers at the given PC in this frame.
203     **/
204    Dwarf_Fde fde;
205    Address u1, u2;
206    if (!getFDE(pc, fde, u1, u2, err_result)) {
207         assert(err_result != FE_No_Error);
208       return false;
209    }
210
211    Dwarf_Half dwarf_reg;
212    if (!getDwarfReg(reg, fde, dwarf_reg, err_result)) {
213         assert(err_result != FE_No_Error);
214       return false;
215    }
216
217    Address ignored;
218    return getRegAtFrame_aux(pc, fde, dwarf_reg, reg, cons, ignored, err_result);
219 }
220
221 bool DwarfFrameParser::getRegAtFrame_aux(Address pc,
222                                          Dwarf_Fde fde,
223                                          Dwarf_Half dwarf_reg,
224                                          MachRegister orig_reg,
225                                          DwarfResult &cons,
226                                          Address &lowpc,
227                                          FrameErrors_t &err_result) {
228    int result;
229    Dwarf_Error err;
230
231    int width = getArchAddressWidth(arch);
232
233    Dwarf_Small value_type;
234    Dwarf_Signed offset_relevant, register_num, offset_or_block_len;
235    Dwarf_Ptr block_ptr;
236    Dwarf_Addr row_pc;
237
238    /**
239     * Decode the rule that describes how to get dwarf_reg at pc.
240     **/
241    if (dwarf_reg != DW_FRAME_CFA_COL3) {
242       result = dwarf_get_fde_info_for_reg3(fde, dwarf_reg, pc, &value_type, 
243                                            &offset_relevant, &register_num,
244                                            &offset_or_block_len,
245                                            &block_ptr, &row_pc, &err);
246    }
247    else {
248       result = dwarf_get_fde_info_for_cfa_reg3(fde, pc, &value_type, 
249                                                &offset_relevant, &register_num,
250                                                &offset_or_block_len,
251                                                &block_ptr, &row_pc, &err);
252    }
253    if (result == DW_DLV_ERROR) {
254       err_result = FE_Bad_Frame_Data;
255       return false;
256    }
257
258    lowpc = (Address) row_pc;
259
260    /**
261     * Interpret the rule and turn it into a real value.
262     **/
263    
264    if (value_type == DW_EXPR_OFFSET || value_type == DW_EXPR_VAL_OFFSET)
265    {
266       bool done;
267       if (!handleExpression(pc, register_num, orig_reg,
268                             arch, cons, done, err_result)) {
269         assert(err_result != FE_No_Error);
270         return false;
271       }
272       if (done) return true;
273    }
274
275    bool indirect = false;
276
277    switch(value_type) {
278       // For a val offset, the value of the register is (other_reg + const)
279       case DW_EXPR_VAL_OFFSET:
280       case DW_EXPR_OFFSET:
281          if (offset_relevant) {
282             cons.pushSignedVal(offset_or_block_len);
283             cons.pushOp(DwarfResult::Add);
284          }
285          
286          if (offset_relevant && 
287              dwarf_reg != DW_FRAME_CFA_COL3) {
288             indirect = true;
289          }
290          break;
291       case DW_EXPR_VAL_EXPRESSION:
292       case DW_EXPR_EXPRESSION: {
293          Dwarf_Locdesc *llbuf = NULL;
294          Dwarf_Signed listlen = 0;
295          result = dwarf_loclist_from_expr(dbg, block_ptr, offset_or_block_len, &llbuf, &listlen, &err);
296          if (result != DW_DLV_OK) {
297            err_result = FE_Frame_Read_Error;
298             return false;
299          }
300          
301          if (!decodeDwarfExpression(llbuf, NULL, 
302                                     cons,
303                                     arch)) {
304            err_result = FE_Frame_Eval_Error;
305             return false;
306          }
307
308          dwarf_dealloc(dbg, llbuf->ld_s, DW_DLA_LOC_BLOCK);
309          dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC);
310          
311          if (value_type == DW_EXPR_EXPRESSION) {
312             indirect = true;
313          }
314          break;
315       }
316       default:
317          err_result = FE_Bad_Frame_Data;
318          return false;
319    }
320    
321    if (indirect) {
322       cons.pushOp(DwarfResult::Deref, width);
323    }
324
325    return true;
326 }
327
328 void DwarfFrameParser::setupFdeData()
329 {
330    Dwarf_Error err;
331    
332    if (fde_dwarf_status == dwarf_status_ok || 
333        fde_dwarf_status == dwarf_status_error)
334       return;
335
336    if (!dbg) {
337       fde_dwarf_status = dwarf_status_error;
338       return;
339    }
340
341 #if defined(dwarf_has_setframe)
342    dwarf_set_frame_cfa_value(dbg, DW_FRAME_CFA_COL3);
343 #endif
344
345    fde_cie_data fc;
346    int result = dwarf_get_fde_list(dbg, 
347                                    &fc.cie_data, &fc.cie_count,
348                                    &fc.fde_data, &fc.fde_count,
349                                    &err);
350    if (result == DW_DLV_OK) {
351       fde_data.push_back(fc);
352    }
353
354    result = dwarf_get_fde_list_eh(dbg, 
355                                   &fc.cie_data, &fc.cie_count,
356                                   &fc.fde_data, &fc.fde_count,
357                                   &err);
358    if (result == DW_DLV_OK) {
359       fde_data.push_back(fc);
360    }
361    
362
363    if (!fde_data.size()) {
364       fde_dwarf_status = dwarf_status_error;
365    }
366    
367    fde_dwarf_status = dwarf_status_ok;
368 }
369
370 bool DwarfFrameParser::getFDE(Address pc, Dwarf_Fde &fde, 
371                               Address &low, Address &high, 
372                               FrameErrors_t &err_result) {
373    Dwarf_Addr lowpc = 0, hipc = 0;
374
375    bool found = false;
376    unsigned cur_fde;
377    for (cur_fde=0; cur_fde<fde_data.size(); cur_fde++) {
378       int result = dwarf_get_fde_at_pc(fde_data[cur_fde].fde_data, 
379                                        (Dwarf_Addr) pc, &fde, &lowpc, &hipc, NULL);
380       if (result == DW_DLV_ERROR) {
381          err_result = FE_Bad_Frame_Data;
382          return false;
383       }
384       else if (result == DW_DLV_OK) {
385          low = (Address) lowpc;
386          high = (Address) hipc;
387          found = true;
388          break;
389       }
390    }
391    if (!found)
392    {
393       err_result = FE_No_Frame_Entry;
394       return false;
395    }
396    return true;
397 }
398
399 bool DwarfFrameParser::getDwarfReg(Dyninst::MachRegister reg,
400                                    Dwarf_Fde &fde,
401                                    Dwarf_Half &dwarf_reg,
402                                    FrameErrors_t &err_result) {
403    Dwarf_Error err;
404    if (reg == Dyninst::ReturnAddr) {
405       /**
406        * We should be getting the return address for the stack frame.  
407        * This is treated as a virtual register in the
408        * FDE.  We can look up the virtual register in the CIE.
409        **/
410       Dwarf_Cie cie;
411       int result = dwarf_get_cie_of_fde(fde, &cie, &err);
412       if (result != DW_DLV_OK) {
413          err_result = FE_Bad_Frame_Data;
414          return false;
415       }
416
417       Dwarf_Unsigned bytes_in_cie;
418       result = dwarf_get_cie_info(cie, &bytes_in_cie, NULL, NULL, NULL, NULL, 
419                                   &dwarf_reg, NULL, NULL, &err);
420       if (result != DW_DLV_OK) {
421          err_result = FE_Bad_Frame_Data;
422          return false;
423       }
424    }
425    else if (reg == Dyninst::FrameBase || reg == Dyninst::CFA) {
426       dwarf_reg = DW_FRAME_CFA_COL3;
427    }
428    else {
429       dwarf_reg = reg.getDwarfEnc(); 
430    }
431    return true;
432 }
433
434 bool DwarfFrameParser::handleExpression(Address pc,
435                                Dwarf_Signed registerNum,
436                                Dyninst::MachRegister origReg,
437                                Dyninst::Architecture arch,
438                                DwarfResult &cons,
439                                bool &done,
440                                FrameErrors_t &err_result) {
441    done = false;
442    switch (registerNum) {
443       case DW_FRAME_CFA_COL3:
444          err_result = FE_No_Error;
445          if (!getRegAtFrame(pc, Dyninst::FrameBase,
446                             cons, err_result)) {
447            assert(err_result != FE_No_Error);
448             return false;
449          }
450          break;
451       case DW_FRAME_SAME_VAL:
452          cons.readReg(origReg);
453          done = true;
454          break;
455       default: {
456          Dyninst::MachRegister dyn_register = MachRegister::DwarfEncToReg(registerNum, arch);
457          cons.readReg(dyn_register);
458          break;
459       }
460    }
461    return true;
462 }  
463