xref: /titanic_50/usr/src/lib/libdwarf/common/dwarf_frame3.c (revision 2a52a1627973d84afe3af6de87c1fe00ac3d087e)
1 /*
2 
3   Copyright (C) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
4   Portions Copyright (C) 2009-2010 David Anderson. All Rights Reserved.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of version 2.1 of the GNU Lesser General Public License
8   as published by the Free Software Foundation.
9 
10   This program is distributed in the hope that it would be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14   Further, this software is distributed without any warranty that it is
15   free of the rightful claim of any third person regarding infringement
16   or the like.  Any license provided herein, whether implied or
17   otherwise, applies only to this software file.  Patent licenses, if
18   any, provided herein do not apply to combinations of this program with
19   other software, or any other product whatsoever.
20 
21   You should have received a copy of the GNU Lesser General Public
22   License along with this program; if not, write the Free Software
23   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
24   USA.
25 
26   Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
27   Mountain View, CA 94043, or:
28 
29   http://www.sgi.com
30 
31   For further information regarding this notice, see:
32 
33   http://oss.sgi.com/projects/GenInfo/NoticeExplan
34 
35 */
36 
37 
38 
39 #include "config.h"
40 #include "dwarf_incl.h"
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include "dwarf_frame.h"
44 #include "dwarf_arange.h" /* using Arange as a way to build a list */
45 
46 /*
47     Used by rqs (an IRIX application).
48     Not needed except for that one application.
49     Should be moved to its own source file since
50     it is so rarely needed.
51     Returns DW_DLV_OK if returns the arrays.
52     Returns DW_DLV_NO_ENTRY if no section. ?? (How do I tell?)
53     Returns DW_DLV_ERROR if there is an error.
54 
55     Uses DW_FRAME_CFA_COL because IRIX is only DWARF2
56     and that is what IRIX compilers and compatible
57     compilers support on IRIX.
58 */
59 int
60 _dwarf_frame_address_offsets(Dwarf_Debug dbg, Dwarf_Addr ** addrlist,
61                              Dwarf_Off ** offsetlist,
62                              Dwarf_Signed * returncount,
63                              Dwarf_Error * err)
64 {
65     int retval = DW_DLV_OK;
66     int res = DW_DLV_ERROR;
67     Dwarf_Cie *cie_data;
68     Dwarf_Signed cie_count;
69     Dwarf_Fde *fde_data;
70     Dwarf_Signed fde_count;
71     Dwarf_Signed i;
72     Dwarf_Frame_Op *frame_inst;
73     Dwarf_Fde fdep;
74     Dwarf_Cie ciep;
75     Dwarf_Chain curr_chain = 0;
76     Dwarf_Chain head_chain = 0;
77     Dwarf_Chain prev_chain = 0;
78     Dwarf_Arange arange;
79     Dwarf_Unsigned arange_count = 0;
80     Dwarf_Addr *arange_addrs = 0;
81     Dwarf_Off *arange_offsets = 0;
82 
83     res = dwarf_get_fde_list(dbg, &cie_data, &cie_count,
84                              &fde_data, &fde_count, err);
85     if (res != DW_DLV_OK) {
86         return res;
87     }
88 
89     res = _dwarf_load_section(dbg, &dbg->de_debug_frame, err);
90     if (res != DW_DLV_OK) {
91         return res;
92     }
93 
94     for (i = 0; i < cie_count; i++) {
95         Dwarf_Off instoff = 0;
96         Dwarf_Signed initial_instructions_length = 0;
97         Dwarf_Small *instr_end = 0;
98         Dwarf_Sword icount = 0;
99         int j = 0;
100         int dw_err;
101 
102         ciep = cie_data[i];
103         instoff = ciep->ci_cie_instr_start - dbg->de_debug_frame.dss_data;
104         initial_instructions_length = ciep->ci_length +
105             ciep->ci_length_size + ciep->ci_extension_size -
106             (ciep->ci_cie_instr_start - ciep->ci_cie_start);
107         instr_end = ciep->ci_cie_instr_start +
108             initial_instructions_length;
109         res = _dwarf_exec_frame_instr( /* make_instr */ true,
110             &frame_inst,
111             /* search_pc= */ false,
112             /* search_pc_val= */ 0,
113             /* location */ 0,
114             ciep->ci_cie_instr_start,
115             instr_end,
116             /* Dwarf_frame= */ 0,
117             /* cie= */ 0,
118             dbg,
119             DW_FRAME_CFA_COL,
120             &icount, &dw_err);
121         if (res == DW_DLV_ERROR) {
122             _dwarf_error(dbg, err, dw_err);
123             return (res);
124         } else if (res == DW_DLV_NO_ENTRY) {
125             continue;
126         }
127 
128         for (j = 0; j < icount; ++j) {
129             Dwarf_Frame_Op *finst = frame_inst + j;
130 
131             if (finst->fp_base_op == 0 && finst->fp_extended_op == 1) {
132                 /* is DW_CFA_set_loc */
133                 Dwarf_Addr add = (Dwarf_Addr) finst->fp_offset;
134                 Dwarf_Off off = finst->fp_instr_offset + instoff;
135 
136                 arange = (Dwarf_Arange)
137                     _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
138                 if (arange == NULL) {
139                     _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
140                     return (DW_DLV_ERROR);
141                 }
142                 arange->ar_address = add;
143                 arange->ar_info_offset = off;
144                 arange_count++;
145                 curr_chain = (Dwarf_Chain)
146                     _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
147                 if (curr_chain == NULL) {
148                     _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
149                     return (DW_DLV_ERROR);
150                 }
151                 curr_chain->ch_item = arange;
152                 if (head_chain == NULL)
153                     head_chain = prev_chain = curr_chain;
154                 else {
155                     prev_chain->ch_next = curr_chain;
156                     prev_chain = curr_chain;
157                 }
158             }
159         }
160         dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK);
161 
162     }
163     for (i = 0; i < fde_count; i++) {
164         Dwarf_Small *instr_end = 0;
165         Dwarf_Sword icount = 0;
166         Dwarf_Signed instructions_length = 0;
167         Dwarf_Off instoff = 0;
168         Dwarf_Off off = 0;
169         Dwarf_Addr addr = 0;
170         int j = 0;
171         int dw_err;
172 
173         fdep = fde_data[i];
174         off = fdep->fd_initial_loc_pos - dbg->de_debug_frame.dss_data;
175         addr = fdep->fd_initial_location;
176         arange = (Dwarf_Arange)
177             _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
178         if (arange == NULL) {
179             _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
180             return (DW_DLV_ERROR);
181         }
182         arange->ar_address = addr;
183         arange->ar_info_offset = off;
184         arange_count++;
185         curr_chain = (Dwarf_Chain)
186             _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
187         if (curr_chain == NULL) {
188             _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
189             return (DW_DLV_ERROR);
190         }
191         curr_chain->ch_item = arange;
192         if (head_chain == NULL)
193             head_chain = prev_chain = curr_chain;
194         else {
195             prev_chain->ch_next = curr_chain;
196             prev_chain = curr_chain;
197         }
198 
199 
200         instoff = fdep->fd_fde_instr_start - dbg->de_debug_frame.dss_data;
201         instructions_length = fdep->fd_length +
202             fdep->fd_length_size + fdep->fd_extension_size -
203             (fdep->fd_fde_instr_start - fdep->fd_fde_start);
204         instr_end = fdep->fd_fde_instr_start + instructions_length;
205         res = _dwarf_exec_frame_instr( /* make_instr */ true,
206             &frame_inst,
207             /* search_pc= */ false,
208             /* search_pc_val= */ 0,
209             /* location */ 0,
210             fdep->fd_fde_instr_start,
211             instr_end,
212             /* Dwarf_frame= */ 0,
213             /* cie= */ 0,
214             dbg,
215             DW_FRAME_CFA_COL,
216             &icount, &dw_err);
217         if (res == DW_DLV_ERROR) {
218             _dwarf_error(dbg, err, dw_err);
219             return (res);
220         } else if (res == DW_DLV_NO_ENTRY) {
221             continue;
222         }
223 
224         for (j = 0; j < icount; ++j) {
225             Dwarf_Frame_Op *finst2 = frame_inst + j;
226 
227             if (finst2->fp_base_op == 0 && finst2->fp_extended_op == 1) {
228                 /* is DW_CFA_set_loc */
229                 Dwarf_Addr add = (Dwarf_Addr) finst2->fp_offset;
230                 Dwarf_Off off = finst2->fp_instr_offset + instoff;
231 
232                 arange = (Dwarf_Arange)
233                     _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
234                 if (arange == NULL) {
235                     _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
236                     return (DW_DLV_ERROR);
237                 }
238                 arange->ar_address = add;
239                 arange->ar_info_offset = off;
240                 arange_count++;
241                 curr_chain = (Dwarf_Chain)
242                     _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
243                 if (curr_chain == NULL) {
244                     _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
245                     return (DW_DLV_ERROR);
246                 }
247                 curr_chain->ch_item = arange;
248                 if (head_chain == NULL)
249                     head_chain = prev_chain = curr_chain;
250                 else {
251                     prev_chain->ch_next = curr_chain;
252                     prev_chain = curr_chain;
253                 }
254 
255             }
256         }
257         dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK);
258 
259     }
260     dwarf_dealloc(dbg, fde_data, DW_DLA_LIST);
261     dwarf_dealloc(dbg, cie_data, DW_DLA_LIST);
262     arange_addrs = (Dwarf_Addr *)
263         _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
264     if (arange_addrs == NULL) {
265         _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
266         return (DW_DLV_ERROR);
267     }
268     arange_offsets = (Dwarf_Off *)
269         _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
270     if (arange_offsets == NULL) {
271         _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
272         return (DW_DLV_ERROR);
273     }
274 
275     curr_chain = head_chain;
276     for (i = 0; i < arange_count; i++) {
277         Dwarf_Arange ar = curr_chain->ch_item;
278 
279         arange_addrs[i] = ar->ar_address;
280         arange_offsets[i] = ar->ar_info_offset;
281         prev_chain = curr_chain;
282         curr_chain = curr_chain->ch_next;
283         dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
284         dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
285     }
286     *returncount = arange_count;
287     *offsetlist = arange_offsets;
288     *addrlist = arange_addrs;
289     return retval;
290 }
291