Build fixes for static linked Dyninst components (compute node linux), when linking...
[dyninst.git] / common / h / dwarfSW.h
1 /*
2  * Copyright (c) 1996-2011 Barton P. Miller
3  * 
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.
10  * 
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.
16  * 
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.
21  * 
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.
26  * 
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
30  */
31
32 #if !defined(DWARF_SW_H_)
33 #define DWARF_SW_H_
34
35 #include "libdwarf.h"
36
37 typedef struct {
38   Dwarf_Fde *fde_data;
39   Dwarf_Signed fde_count;
40   Dwarf_Cie *cie_data;
41   Dwarf_Signed cie_count;   
42 } fde_cie_data;
43
44 class DwarfSW {
45    typedef enum {
46       dwarf_status_uninitialized,
47       dwarf_status_error,
48       dwarf_status_ok
49    } dwarf_status_t;
50    Dwarf_Debug dbg;
51    unsigned addr_width;
52    dwarf_status_t fde_dwarf_status;
53
54    std::vector<fde_cie_data> fde_data;
55    void setupFdeData();
56   public:
57    DwarfSW(Dwarf_Debug dbg_, unsigned addr_width_);
58    ~DwarfSW();
59
60    bool hasFrameDebugInfo();
61    bool getRegValueAtFrame(Address pc, 
62                            Dyninst::MachRegister reg, 
63                            Dyninst::MachRegisterVal &reg_result,
64                            Dyninst::Architecture arch,
65                            ProcessReader *reader);
66 };
67
68 inline DwarfSW::DwarfSW(Dwarf_Debug dbg_, unsigned addr_width_) :
69    dbg(dbg_),
70    addr_width(addr_width_),
71    fde_dwarf_status(dwarf_status_uninitialized)
72 {
73 }
74
75 inline DwarfSW::~DwarfSW()
76 {
77    if (fde_dwarf_status != dwarf_status_ok) 
78       return;
79    for (unsigned i=0; i<fde_data.size(); i++)
80    {
81       dwarf_fde_cie_list_dealloc(dbg, 
82                                  fde_data[i].cie_data, fde_data[i].cie_count, 
83                                  fde_data[i].fde_data, fde_data[i].fde_count);
84    }
85 }
86
87 inline bool DwarfSW::hasFrameDebugInfo()
88 {
89    setupFdeData();
90    return fde_dwarf_status == dwarf_status_ok;
91 }
92
93 inline bool DwarfSW::getRegValueAtFrame(Address pc, 
94                                         Dyninst::MachRegister reg,
95                                         Dyninst::MachRegisterVal &reg_result,
96                                         Dyninst::Architecture arch,
97                                         ProcessReader *reader)
98 {
99         int result;
100         Dwarf_Fde fde;
101         Dwarf_Addr lowpc, hipc;
102         Dwarf_Error err;
103
104         /**
105          * Initialize the FDE and CIE data.  This is only really done once, 
106          * after which setupFdeData will immediately return.
107     **/
108    setupFdeData();
109    if (!fde_data.size()) {
110       setSymtabError(Bad_Frame_Data);
111       return false;
112    }
113
114
115    /**
116     * Get the FDE at this PC.  The FDE contains the rules for getting
117     * registers at the given PC in this frame.
118     **/
119    bool found = false;
120    unsigned cur_fde;
121    for (cur_fde=0; cur_fde<fde_data.size(); cur_fde++)
122    {
123       result = dwarf_get_fde_at_pc(fde_data[cur_fde].fde_data, 
124                                    (Dwarf_Addr) pc, &fde, &lowpc, &hipc, &err);
125       if (result == DW_DLV_ERROR)
126       {
127          setSymtabError(Bad_Frame_Data);
128          return false;
129       }
130       else if (result == DW_DLV_OK) {
131          found = true;
132          break;
133       }
134    }
135    if (!found)
136    {
137       setSymtabError(No_Frame_Entry);
138       return false;
139    }
140
141    Dwarf_Half dwarf_reg;
142    if (reg == Dyninst::ReturnAddr) {
143       /**
144        * We should be getting the return address for the stack frame.  
145        * This is treated as a virtual register in the
146        * FDE.  We can look up the virtual register in the CIE.
147        **/
148       Dwarf_Cie cie;
149       result = dwarf_get_cie_of_fde(fde, &cie, &err);
150       if (result != DW_DLV_OK) {
151          setSymtabError(Bad_Frame_Data);
152          return false;
153       }
154
155       Dwarf_Unsigned bytes_in_cie;
156       result = dwarf_get_cie_info(cie, &bytes_in_cie, NULL, NULL, NULL, NULL, 
157                                   &dwarf_reg, NULL, NULL, &err);
158       if (result != DW_DLV_OK) {
159          setSymtabError(Bad_Frame_Data);
160          return false;
161       }
162    }
163    else if (reg == Dyninst::FrameBase) {
164       dwarf_reg = DW_FRAME_CFA_COL3;
165    }
166    else {
167       dwarf_reg = DynToDwarfReg(reg);
168    }
169
170    Dwarf_Small value_type;
171    Dwarf_Signed offset_relevant, register_num, offset_or_block_len;
172    Dwarf_Ptr block_ptr;
173    Dwarf_Addr row_pc;
174
175    /**
176     * Decode the rule that describes how to get dwarf_reg at pc.
177     **/
178    if (dwarf_reg != DW_FRAME_CFA_COL3) {
179       result = dwarf_get_fde_info_for_reg3(fde, dwarf_reg, pc, &value_type, 
180                                            &offset_relevant, &register_num,
181                                            &offset_or_block_len,
182                                            &block_ptr, &row_pc, &err);
183    }
184    else {
185       result = dwarf_get_fde_info_for_cfa_reg3(fde, pc, &value_type, 
186                                                &offset_relevant, &register_num,
187                                                &offset_or_block_len,
188                                                &block_ptr, &row_pc, &err);
189    }
190    if (result == DW_DLV_ERROR) {
191       setSymtabError(Bad_Frame_Data);
192       return false;
193    }
194
195    /**
196     * Interpret the rule and turn it into a real value.
197     **/
198    unsigned word_size = addr_width;
199
200    Dyninst::Address res_addr = 0;
201    Dyninst::MachRegisterVal register_val;
202    
203    if (value_type == DW_EXPR_OFFSET || value_type == DW_EXPR_VAL_OFFSET)
204    {
205       if (register_num == DW_FRAME_CFA_COL3) {
206          bool bresult = getRegValueAtFrame(pc, Dyninst::FrameBase,
207                                            register_val, arch, reader);
208          if (!bresult) 
209             return false;
210       }
211       else if (register_num == DW_FRAME_SAME_VAL) {
212          bool bresult = reader->GetReg(reg, register_val);
213          if (!bresult) {
214             setSymtabError(Frame_Read_Error);
215             return false;
216          }
217          reg_result = register_val;
218          return true;
219       }
220       else {
221          Dyninst::MachRegister dyn_registr = DwarfToDynReg(register_num, arch);
222          bool bresult = reader->GetReg(dyn_registr, register_val);
223          if (!bresult) {
224             setSymtabError(Frame_Read_Error);
225             return false;
226          }
227       }
228    }
229
230    if ((value_type == DW_EXPR_VAL_OFFSET) || 
231        (value_type == DW_EXPR_OFFSET && dwarf_reg == DW_FRAME_CFA_COL3)) {
232       assert(offset_relevant);
233       reg_result = (Dyninst::MachRegisterVal) (register_val + offset_or_block_len);
234       return true;
235    }
236    else if (value_type == DW_EXPR_OFFSET && offset_relevant) {
237       res_addr = (Dyninst::Address) (register_val + offset_or_block_len);
238    }
239    else if (value_type == DW_EXPR_OFFSET && !offset_relevant)
240    {
241       reg_result = register_val;
242       return true;
243    } 
244    else if (value_type == DW_EXPR_VAL_EXPRESSION || value_type == DW_EXPR_EXPRESSION)
245    {
246       Dwarf_Locdesc *llbuf = NULL;
247       Dwarf_Signed listlen = 0;
248       result = dwarf_loclist_from_expr(dbg, block_ptr, offset_or_block_len, &llbuf, &listlen, &err);
249       if (result != DW_DLV_OK) {
250          return false;
251       }
252       
253       bool locset = false;
254       long int end_result = 0;
255       bool bresult = decodeDwarfExpression(llbuf, NULL, NULL, locset, reader, 
256                                            arch, end_result);
257       dwarf_dealloc(dbg, llbuf->ld_s, DW_DLA_LOC_BLOCK);
258       dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC);
259       if (bresult && value_type == DW_EXPR_EXPRESSION) {
260          if (word_size == 4) {
261             uint32_t r;
262             bresult = reader->ReadMem((Dyninst::Address) end_result, &r, 4);
263             reg_result = r;
264          }
265          else if (word_size == 8) {
266             uint64_t r;
267             bresult = reader->ReadMem((Dyninst::Address) end_result, &r, 8);
268             reg_result = r;
269          }
270          else {
271             assert(0); //Unknown word size
272          }
273       }
274       else if (bresult && value_type == DW_EXPR_VAL_EXPRESSION) {
275          reg_result = end_result;
276       }
277       return bresult;
278    }
279    else
280    {
281       setSymtabError(Bad_Frame_Data);
282       return false;
283    }
284    
285    assert(res_addr);
286    bool bresult = false;
287    if (word_size == 4) {
288       uint32_t i;
289       bresult = reader->ReadMem(res_addr, &i, word_size);
290       reg_result = (Dyninst::MachRegisterVal) i;
291    }
292    else if (word_size == 8) {
293       uint64_t i;
294       bresult = reader->ReadMem(res_addr, &i, word_size);
295       reg_result = (Dyninst::MachRegisterVal) i;
296    }
297    if (!bresult) {
298       setSymtabError(Frame_Read_Error);
299       return false;
300    }
301
302    return true;
303 }
304
305 inline void DwarfSW::setupFdeData()
306 {
307    Dwarf_Error err;
308    
309    if (fde_dwarf_status == dwarf_status_ok || 
310        fde_dwarf_status == dwarf_status_error)
311       return;
312
313    if (!dbg) {
314       fde_dwarf_status = dwarf_status_error;
315       return;
316    }
317
318 #if defined(dwarf_has_setframe)
319    dwarf_set_frame_cfa_value(dbg, DW_FRAME_CFA_COL3);
320 #endif
321
322    fde_cie_data fc;
323    int result = dwarf_get_fde_list(dbg, 
324                                    &fc.cie_data, &fc.cie_count,
325                                    &fc.fde_data, &fc.fde_count,
326                                    &err);
327    if (result == DW_DLV_OK) {
328       fde_data.push_back(fc);
329    }
330
331    result = dwarf_get_fde_list_eh(dbg, 
332                                   &fc.cie_data, &fc.cie_count,
333                                   &fc.fde_data, &fc.fde_count,
334                                   &err);
335    if (result == DW_DLV_OK) {
336       fde_data.push_back(fc);
337    }
338
339    if (!fde_data.size()) {
340       fde_dwarf_status = dwarf_status_error;
341    }
342    
343    fde_dwarf_status = dwarf_status_ok;
344 }
345
346 #endif