1/*
2
3  Copyright (C) 2000,2002,2004,2005,2006 Silicon Graphics, Inc.  All Rights Reserved.
4
5  This program is free software; you can redistribute it and/or modify it
6  under the terms of version 2.1 of the GNU Lesser General Public License
7  as published by the Free Software Foundation.
8
9  This program is distributed in the hope that it would be useful, but
10  WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13  Further, this software is distributed without any warranty that it is
14  free of the rightful claim of any third person regarding infringement
15  or the like.  Any license provided herein, whether implied or
16  otherwise, applies only to this software file.  Patent licenses, if
17  any, provided herein do not apply to combinations of this program with
18  other software, or any other product whatsoever.
19
20  You should have received a copy of the GNU Lesser General Public
21  License along with this program; if not, write the Free Software
22  Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
23  USA.
24
25  Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
26  Mountain View, CA 94043, or:
27
28  http://www.sgi.com
29
30  For further information regarding this notice, see:
31
32  http://oss.sgi.com/projects/GenInfo/NoticeExplan
33
34*/
35
36
37
38#include "config.h"
39#include "dwarf_incl.h"
40#include <stdio.h>
41#include <stdlib.h>
42#include "dwarf_frame.h"
43#include "dwarf_arange.h"	/* using Arange as a way to build a
44				   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*/
59int
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;
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 =
90	_dwarf_load_section(dbg,
91			    dbg->de_debug_frame_index,
92			    &dbg->de_debug_frame, err);
93    if (res != DW_DLV_OK) {
94	return res;
95    }
96
97    for (i = 0; i < cie_count; i++) {
98	Dwarf_Off instoff = 0;
99	Dwarf_Signed initial_instructions_length = 0;
100	Dwarf_Small *instr_end = 0;
101	Dwarf_Sword icount = 0;
102	int j;
103	int dw_err;
104
105	ciep = cie_data[i];
106	instoff = ciep->ci_cie_instr_start - dbg->de_debug_frame;
107	initial_instructions_length = ciep->ci_length +
108	    ciep->ci_length_size + ciep->ci_extension_size -
109	    (ciep->ci_cie_instr_start - ciep->ci_cie_start);
110	instr_end = ciep->ci_cie_instr_start +
111	    initial_instructions_length;
112	res = _dwarf_exec_frame_instr( /* make_instr */ true,
113				      &frame_inst,
114				      /* search_pc= */ false,
115				      /* search_pc_val= */ 0,
116				      /* location */ 0,
117				      ciep->ci_cie_instr_start,
118				      instr_end,
119				      /* Dwarf_frame= */ 0,
120				      /* cie= */ 0,
121				      dbg,
122				      DW_FRAME_CFA_COL,
123				      &icount, &dw_err);
124	if (res == DW_DLV_ERROR) {
125	    _dwarf_error(dbg, err, dw_err);
126	    return (res);
127	} else if (res == DW_DLV_NO_ENTRY) {
128	    continue;
129	}
130
131	for (j = 0; j < icount; ++j) {
132	    Dwarf_Frame_Op *finst = frame_inst + j;
133
134	    if (finst->fp_base_op == 0 && finst->fp_extended_op == 1) {
135		/* is DW_CFA_set_loc */
136		Dwarf_Addr add = (Dwarf_Addr) finst->fp_offset;
137		Dwarf_Off off = finst->fp_instr_offset + instoff;
138
139		arange = (Dwarf_Arange)
140		    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
141		if (arange == NULL) {
142		    _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
143		    return (DW_DLV_ERROR);
144		}
145		arange->ar_address = add;
146		arange->ar_info_offset = off;
147		arange_count++;
148		curr_chain = (Dwarf_Chain)
149		    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
150		if (curr_chain == NULL) {
151		    _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
152		    return (DW_DLV_ERROR);
153		}
154		curr_chain->ch_item = arange;
155		if (head_chain == NULL)
156		    head_chain = prev_chain = curr_chain;
157		else {
158		    prev_chain->ch_next = curr_chain;
159		    prev_chain = curr_chain;
160		}
161	    }
162	}
163	dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK);
164
165    }
166    for (i = 0; i < fde_count; i++) {
167	Dwarf_Small *instr_end = 0;
168	Dwarf_Sword icount = 0;
169	Dwarf_Signed instructions_length = 0;
170	Dwarf_Off instoff = 0;
171	Dwarf_Off off = 0;
172	Dwarf_Addr addr = 0;
173	int j;
174	int dw_err;
175
176	fdep = fde_data[i];
177	off = fdep->fd_initial_loc_pos - dbg->de_debug_frame;
178	addr = fdep->fd_initial_location;
179	arange = (Dwarf_Arange)
180	    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
181	if (arange == NULL) {
182	    _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
183	    return (DW_DLV_ERROR);
184	}
185	arange->ar_address = addr;
186	arange->ar_info_offset = off;
187	arange_count++;
188	curr_chain = (Dwarf_Chain)
189	    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
190	if (curr_chain == NULL) {
191	    _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
192	    return (DW_DLV_ERROR);
193	}
194	curr_chain->ch_item = arange;
195	if (head_chain == NULL)
196	    head_chain = prev_chain = curr_chain;
197	else {
198	    prev_chain->ch_next = curr_chain;
199	    prev_chain = curr_chain;
200	}
201
202
203	instoff = fdep->fd_fde_instr_start - dbg->de_debug_frame;
204	instructions_length = fdep->fd_length +
205	    fdep->fd_length_size + fdep->fd_extension_size -
206	    (fdep->fd_fde_instr_start - fdep->fd_fde_start);
207	instr_end = fdep->fd_fde_instr_start + instructions_length;
208	res = _dwarf_exec_frame_instr( /* make_instr */ true,
209				      &frame_inst,
210				      /* search_pc= */ false,
211				      /* search_pc_val= */ 0,
212				      /* location */ 0,
213				      fdep->fd_fde_instr_start,
214				      instr_end,
215				      /* Dwarf_frame= */ 0,
216				      /* cie= */ 0,
217				      dbg,
218				      DW_FRAME_CFA_COL,
219				      &icount, &dw_err);
220	if (res == DW_DLV_ERROR) {
221	    _dwarf_error(dbg, err, dw_err);
222	    return (res);
223	} else if (res == DW_DLV_NO_ENTRY) {
224	    continue;
225	}
226
227	for (j = 0; j < icount; ++j) {
228	    Dwarf_Frame_Op *finst2 = frame_inst + j;
229
230	    if (finst2->fp_base_op == 0 && finst2->fp_extended_op == 1) {
231		/* is DW_CFA_set_loc */
232		Dwarf_Addr add = (Dwarf_Addr) finst2->fp_offset;
233		Dwarf_Off off = finst2->fp_instr_offset + instoff;
234
235		arange = (Dwarf_Arange)
236		    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
237		if (arange == NULL) {
238		    _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
239		    return (DW_DLV_ERROR);
240		}
241		arange->ar_address = add;
242		arange->ar_info_offset = off;
243		arange_count++;
244		curr_chain = (Dwarf_Chain)
245		    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
246		if (curr_chain == NULL) {
247		    _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
248		    return (DW_DLV_ERROR);
249		}
250		curr_chain->ch_item = arange;
251		if (head_chain == NULL)
252		    head_chain = prev_chain = curr_chain;
253		else {
254		    prev_chain->ch_next = curr_chain;
255		    prev_chain = curr_chain;
256		}
257
258	    }
259	}
260	dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK);
261
262    }
263    dwarf_dealloc(dbg, fde_data, DW_DLA_LIST);
264    dwarf_dealloc(dbg, cie_data, DW_DLA_LIST);
265    arange_addrs = (Dwarf_Addr *)
266	_dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
267    if (arange_addrs == NULL) {
268	_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
269	return (DW_DLV_ERROR);
270    }
271    arange_offsets = (Dwarf_Off *)
272	_dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
273    if (arange_offsets == NULL) {
274	_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
275	return (DW_DLV_ERROR);
276    }
277
278    curr_chain = head_chain;
279    for (i = 0; i < arange_count; i++) {
280	Dwarf_Arange ar = curr_chain->ch_item;
281
282	arange_addrs[i] = ar->ar_address;
283	arange_offsets[i] = ar->ar_info_offset;
284	prev_chain = curr_chain;
285	curr_chain = curr_chain->ch_next;
286	dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
287	dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
288    }
289    *returncount = arange_count;
290    *offsetlist = arange_offsets;
291    *addrlist = arange_addrs;
292    return retval;
293}
294