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