1*0a6a1f1dSLionel Sambuc /* $NetBSD: libdwarf_frame.c,v 1.2 2014/03/09 16:58:04 christos Exp $ */
2*0a6a1f1dSLionel Sambuc
3*0a6a1f1dSLionel Sambuc /*-
4*0a6a1f1dSLionel Sambuc * Copyright (c) 2009-2011 Kai Wang
5*0a6a1f1dSLionel Sambuc * All rights reserved.
6*0a6a1f1dSLionel Sambuc *
7*0a6a1f1dSLionel Sambuc * Redistribution and use in source and binary forms, with or without
8*0a6a1f1dSLionel Sambuc * modification, are permitted provided that the following conditions
9*0a6a1f1dSLionel Sambuc * are met:
10*0a6a1f1dSLionel Sambuc * 1. Redistributions of source code must retain the above copyright
11*0a6a1f1dSLionel Sambuc * notice, this list of conditions and the following disclaimer.
12*0a6a1f1dSLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
13*0a6a1f1dSLionel Sambuc * notice, this list of conditions and the following disclaimer in the
14*0a6a1f1dSLionel Sambuc * documentation and/or other materials provided with the distribution.
15*0a6a1f1dSLionel Sambuc *
16*0a6a1f1dSLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*0a6a1f1dSLionel Sambuc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*0a6a1f1dSLionel Sambuc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*0a6a1f1dSLionel Sambuc * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*0a6a1f1dSLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*0a6a1f1dSLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*0a6a1f1dSLionel Sambuc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*0a6a1f1dSLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*0a6a1f1dSLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*0a6a1f1dSLionel Sambuc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*0a6a1f1dSLionel Sambuc * SUCH DAMAGE.
27*0a6a1f1dSLionel Sambuc */
28*0a6a1f1dSLionel Sambuc
29*0a6a1f1dSLionel Sambuc #include "_libdwarf.h"
30*0a6a1f1dSLionel Sambuc
31*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: libdwarf_frame.c,v 1.2 2014/03/09 16:58:04 christos Exp $");
32*0a6a1f1dSLionel Sambuc ELFTC_VCSID("Id: libdwarf_frame.c 2529 2012-07-29 23:31:12Z kaiwang27 ");
33*0a6a1f1dSLionel Sambuc
34*0a6a1f1dSLionel Sambuc static int
_dwarf_frame_find_cie(Dwarf_FrameSec fs,Dwarf_Unsigned offset,Dwarf_Cie * ret_cie)35*0a6a1f1dSLionel Sambuc _dwarf_frame_find_cie(Dwarf_FrameSec fs, Dwarf_Unsigned offset,
36*0a6a1f1dSLionel Sambuc Dwarf_Cie *ret_cie)
37*0a6a1f1dSLionel Sambuc {
38*0a6a1f1dSLionel Sambuc Dwarf_Cie cie;
39*0a6a1f1dSLionel Sambuc
40*0a6a1f1dSLionel Sambuc STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) {
41*0a6a1f1dSLionel Sambuc if (cie->cie_offset == offset)
42*0a6a1f1dSLionel Sambuc break;
43*0a6a1f1dSLionel Sambuc }
44*0a6a1f1dSLionel Sambuc
45*0a6a1f1dSLionel Sambuc if (cie == NULL)
46*0a6a1f1dSLionel Sambuc return (DW_DLE_NO_ENTRY);
47*0a6a1f1dSLionel Sambuc
48*0a6a1f1dSLionel Sambuc if (ret_cie != NULL)
49*0a6a1f1dSLionel Sambuc *ret_cie = cie;
50*0a6a1f1dSLionel Sambuc
51*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
52*0a6a1f1dSLionel Sambuc }
53*0a6a1f1dSLionel Sambuc
54*0a6a1f1dSLionel Sambuc static int
_dwarf_frame_read_lsb_encoded(Dwarf_Debug dbg,uint64_t * val,uint8_t * data,uint64_t * offsetp,uint8_t encode,Dwarf_Addr pc,Dwarf_Error * error)55*0a6a1f1dSLionel Sambuc _dwarf_frame_read_lsb_encoded(Dwarf_Debug dbg, uint64_t *val, uint8_t *data,
56*0a6a1f1dSLionel Sambuc uint64_t *offsetp, uint8_t encode, Dwarf_Addr pc, Dwarf_Error *error)
57*0a6a1f1dSLionel Sambuc {
58*0a6a1f1dSLionel Sambuc uint8_t application;
59*0a6a1f1dSLionel Sambuc
60*0a6a1f1dSLionel Sambuc if (encode == DW_EH_PE_omit)
61*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
62*0a6a1f1dSLionel Sambuc
63*0a6a1f1dSLionel Sambuc application = encode & 0xf0;
64*0a6a1f1dSLionel Sambuc encode &= 0x0f;
65*0a6a1f1dSLionel Sambuc
66*0a6a1f1dSLionel Sambuc switch (encode) {
67*0a6a1f1dSLionel Sambuc case DW_EH_PE_absptr:
68*0a6a1f1dSLionel Sambuc *val = dbg->read(data, offsetp, dbg->dbg_pointer_size);
69*0a6a1f1dSLionel Sambuc break;
70*0a6a1f1dSLionel Sambuc case DW_EH_PE_uleb128:
71*0a6a1f1dSLionel Sambuc *val = _dwarf_read_uleb128(data, offsetp);
72*0a6a1f1dSLionel Sambuc break;
73*0a6a1f1dSLionel Sambuc case DW_EH_PE_udata2:
74*0a6a1f1dSLionel Sambuc *val = dbg->read(data, offsetp, 2);
75*0a6a1f1dSLionel Sambuc break;
76*0a6a1f1dSLionel Sambuc case DW_EH_PE_udata4:
77*0a6a1f1dSLionel Sambuc *val = dbg->read(data, offsetp, 4);
78*0a6a1f1dSLionel Sambuc break;
79*0a6a1f1dSLionel Sambuc case DW_EH_PE_udata8:
80*0a6a1f1dSLionel Sambuc *val = dbg->read(data, offsetp, 8);
81*0a6a1f1dSLionel Sambuc break;
82*0a6a1f1dSLionel Sambuc case DW_EH_PE_sleb128:
83*0a6a1f1dSLionel Sambuc *val = _dwarf_read_sleb128(data, offsetp);
84*0a6a1f1dSLionel Sambuc break;
85*0a6a1f1dSLionel Sambuc case DW_EH_PE_sdata2:
86*0a6a1f1dSLionel Sambuc *val = (int16_t) dbg->read(data, offsetp, 2);
87*0a6a1f1dSLionel Sambuc break;
88*0a6a1f1dSLionel Sambuc case DW_EH_PE_sdata4:
89*0a6a1f1dSLionel Sambuc *val = (int32_t) dbg->read(data, offsetp, 4);
90*0a6a1f1dSLionel Sambuc break;
91*0a6a1f1dSLionel Sambuc case DW_EH_PE_sdata8:
92*0a6a1f1dSLionel Sambuc *val = dbg->read(data, offsetp, 8);
93*0a6a1f1dSLionel Sambuc break;
94*0a6a1f1dSLionel Sambuc default:
95*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
96*0a6a1f1dSLionel Sambuc return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
97*0a6a1f1dSLionel Sambuc }
98*0a6a1f1dSLionel Sambuc
99*0a6a1f1dSLionel Sambuc if (application == DW_EH_PE_pcrel) {
100*0a6a1f1dSLionel Sambuc /*
101*0a6a1f1dSLionel Sambuc * Value is relative to .eh_frame section virtual addr.
102*0a6a1f1dSLionel Sambuc */
103*0a6a1f1dSLionel Sambuc switch (encode) {
104*0a6a1f1dSLionel Sambuc case DW_EH_PE_uleb128:
105*0a6a1f1dSLionel Sambuc case DW_EH_PE_udata2:
106*0a6a1f1dSLionel Sambuc case DW_EH_PE_udata4:
107*0a6a1f1dSLionel Sambuc case DW_EH_PE_udata8:
108*0a6a1f1dSLionel Sambuc *val += pc;
109*0a6a1f1dSLionel Sambuc break;
110*0a6a1f1dSLionel Sambuc case DW_EH_PE_sleb128:
111*0a6a1f1dSLionel Sambuc case DW_EH_PE_sdata2:
112*0a6a1f1dSLionel Sambuc case DW_EH_PE_sdata4:
113*0a6a1f1dSLionel Sambuc case DW_EH_PE_sdata8:
114*0a6a1f1dSLionel Sambuc *val = pc + (int64_t) *val;
115*0a6a1f1dSLionel Sambuc break;
116*0a6a1f1dSLionel Sambuc default:
117*0a6a1f1dSLionel Sambuc /* DW_EH_PE_absptr is absolute value. */
118*0a6a1f1dSLionel Sambuc break;
119*0a6a1f1dSLionel Sambuc }
120*0a6a1f1dSLionel Sambuc }
121*0a6a1f1dSLionel Sambuc
122*0a6a1f1dSLionel Sambuc /* XXX Applications other than DW_EH_PE_pcrel are not handled. */
123*0a6a1f1dSLionel Sambuc
124*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
125*0a6a1f1dSLionel Sambuc }
126*0a6a1f1dSLionel Sambuc
127*0a6a1f1dSLionel Sambuc static int
_dwarf_frame_parse_lsb_cie_augment(Dwarf_Debug dbg,Dwarf_Cie cie,Dwarf_Error * error)128*0a6a1f1dSLionel Sambuc _dwarf_frame_parse_lsb_cie_augment(Dwarf_Debug dbg, Dwarf_Cie cie,
129*0a6a1f1dSLionel Sambuc Dwarf_Error *error)
130*0a6a1f1dSLionel Sambuc {
131*0a6a1f1dSLionel Sambuc uint8_t *aug_p, *augdata_p;
132*0a6a1f1dSLionel Sambuc uint64_t val, offset;
133*0a6a1f1dSLionel Sambuc uint8_t encode;
134*0a6a1f1dSLionel Sambuc int ret;
135*0a6a1f1dSLionel Sambuc
136*0a6a1f1dSLionel Sambuc assert(cie->cie_augment != NULL && *cie->cie_augment == 'z');
137*0a6a1f1dSLionel Sambuc
138*0a6a1f1dSLionel Sambuc /*
139*0a6a1f1dSLionel Sambuc * Here we're only interested in the presence of augment 'R'
140*0a6a1f1dSLionel Sambuc * and associated CIE augment data, which describes the
141*0a6a1f1dSLionel Sambuc * encoding scheme of FDE PC begin and range.
142*0a6a1f1dSLionel Sambuc */
143*0a6a1f1dSLionel Sambuc aug_p = &cie->cie_augment[1];
144*0a6a1f1dSLionel Sambuc augdata_p = cie->cie_augdata;
145*0a6a1f1dSLionel Sambuc while (*aug_p != '\0') {
146*0a6a1f1dSLionel Sambuc switch (*aug_p) {
147*0a6a1f1dSLionel Sambuc case 'L':
148*0a6a1f1dSLionel Sambuc /* Skip one augment in augment data. */
149*0a6a1f1dSLionel Sambuc augdata_p++;
150*0a6a1f1dSLionel Sambuc break;
151*0a6a1f1dSLionel Sambuc case 'P':
152*0a6a1f1dSLionel Sambuc /* Skip two augments in augment data. */
153*0a6a1f1dSLionel Sambuc encode = *augdata_p++;
154*0a6a1f1dSLionel Sambuc offset = 0;
155*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_read_lsb_encoded(dbg, &val,
156*0a6a1f1dSLionel Sambuc augdata_p, &offset, encode, 0, error);
157*0a6a1f1dSLionel Sambuc if (ret != DW_DLE_NONE)
158*0a6a1f1dSLionel Sambuc return (ret);
159*0a6a1f1dSLionel Sambuc augdata_p += offset;
160*0a6a1f1dSLionel Sambuc break;
161*0a6a1f1dSLionel Sambuc case 'R':
162*0a6a1f1dSLionel Sambuc cie->cie_fde_encode = *augdata_p++;
163*0a6a1f1dSLionel Sambuc break;
164*0a6a1f1dSLionel Sambuc default:
165*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error,
166*0a6a1f1dSLionel Sambuc DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
167*0a6a1f1dSLionel Sambuc return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
168*0a6a1f1dSLionel Sambuc }
169*0a6a1f1dSLionel Sambuc aug_p++;
170*0a6a1f1dSLionel Sambuc }
171*0a6a1f1dSLionel Sambuc
172*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
173*0a6a1f1dSLionel Sambuc }
174*0a6a1f1dSLionel Sambuc
175*0a6a1f1dSLionel Sambuc static int
_dwarf_frame_add_cie(Dwarf_Debug dbg,Dwarf_FrameSec fs,Dwarf_Section * ds,Dwarf_Unsigned * off,Dwarf_Cie * ret_cie,Dwarf_Error * error)176*0a6a1f1dSLionel Sambuc _dwarf_frame_add_cie(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds,
177*0a6a1f1dSLionel Sambuc Dwarf_Unsigned *off, Dwarf_Cie *ret_cie, Dwarf_Error *error)
178*0a6a1f1dSLionel Sambuc {
179*0a6a1f1dSLionel Sambuc Dwarf_Cie cie;
180*0a6a1f1dSLionel Sambuc uint64_t length;
181*0a6a1f1dSLionel Sambuc int dwarf_size, ret;
182*0a6a1f1dSLionel Sambuc char *p;
183*0a6a1f1dSLionel Sambuc
184*0a6a1f1dSLionel Sambuc /* Check if we already added this CIE. */
185*0a6a1f1dSLionel Sambuc if (_dwarf_frame_find_cie(fs, *off, &cie) != DW_DLE_NO_ENTRY) {
186*0a6a1f1dSLionel Sambuc *off += cie->cie_length + 4;
187*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
188*0a6a1f1dSLionel Sambuc }
189*0a6a1f1dSLionel Sambuc
190*0a6a1f1dSLionel Sambuc if ((cie = calloc(1, sizeof(struct _Dwarf_Cie))) == NULL) {
191*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
192*0a6a1f1dSLionel Sambuc return (DW_DLE_MEMORY);
193*0a6a1f1dSLionel Sambuc }
194*0a6a1f1dSLionel Sambuc STAILQ_INSERT_TAIL(&fs->fs_cielist, cie, cie_next);
195*0a6a1f1dSLionel Sambuc
196*0a6a1f1dSLionel Sambuc cie->cie_dbg = dbg;
197*0a6a1f1dSLionel Sambuc cie->cie_index = fs->fs_cielen;
198*0a6a1f1dSLionel Sambuc cie->cie_offset = *off;
199*0a6a1f1dSLionel Sambuc
200*0a6a1f1dSLionel Sambuc length = dbg->read(ds->ds_data, off, 4);
201*0a6a1f1dSLionel Sambuc if (length == 0xffffffff) {
202*0a6a1f1dSLionel Sambuc dwarf_size = 8;
203*0a6a1f1dSLionel Sambuc length = dbg->read(ds->ds_data, off, 8);
204*0a6a1f1dSLionel Sambuc } else
205*0a6a1f1dSLionel Sambuc dwarf_size = 4;
206*0a6a1f1dSLionel Sambuc
207*0a6a1f1dSLionel Sambuc if (length > ds->ds_size - *off) {
208*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
209*0a6a1f1dSLionel Sambuc return (DW_DLE_DEBUG_FRAME_LENGTH_BAD);
210*0a6a1f1dSLionel Sambuc }
211*0a6a1f1dSLionel Sambuc
212*0a6a1f1dSLionel Sambuc (void) dbg->read(ds->ds_data, off, dwarf_size); /* Skip CIE id. */
213*0a6a1f1dSLionel Sambuc cie->cie_length = length;
214*0a6a1f1dSLionel Sambuc
215*0a6a1f1dSLionel Sambuc cie->cie_version = dbg->read(ds->ds_data, off, 1);
216*0a6a1f1dSLionel Sambuc if (cie->cie_version != 1 && cie->cie_version != 3 &&
217*0a6a1f1dSLionel Sambuc cie->cie_version != 4) {
218*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_VERSION_BAD);
219*0a6a1f1dSLionel Sambuc return (DW_DLE_FRAME_VERSION_BAD);
220*0a6a1f1dSLionel Sambuc }
221*0a6a1f1dSLionel Sambuc
222*0a6a1f1dSLionel Sambuc cie->cie_augment = ds->ds_data + *off;
223*0a6a1f1dSLionel Sambuc p = (char *) ds->ds_data;
224*0a6a1f1dSLionel Sambuc while (p[(*off)++] != '\0')
225*0a6a1f1dSLionel Sambuc ;
226*0a6a1f1dSLionel Sambuc
227*0a6a1f1dSLionel Sambuc /* We only recognize normal .dwarf_frame and GNU .eh_frame sections. */
228*0a6a1f1dSLionel Sambuc if (*cie->cie_augment != 0 && *cie->cie_augment != 'z') {
229*0a6a1f1dSLionel Sambuc *off = cie->cie_offset + ((dwarf_size == 4) ? 4 : 12) +
230*0a6a1f1dSLionel Sambuc cie->cie_length;
231*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
232*0a6a1f1dSLionel Sambuc }
233*0a6a1f1dSLionel Sambuc
234*0a6a1f1dSLionel Sambuc /* Optional EH Data field for .eh_frame section. */
235*0a6a1f1dSLionel Sambuc if (strstr((char *)cie->cie_augment, "eh") != NULL)
236*0a6a1f1dSLionel Sambuc cie->cie_ehdata = dbg->read(ds->ds_data, off,
237*0a6a1f1dSLionel Sambuc dbg->dbg_pointer_size);
238*0a6a1f1dSLionel Sambuc
239*0a6a1f1dSLionel Sambuc cie->cie_caf = _dwarf_read_uleb128(ds->ds_data, off);
240*0a6a1f1dSLionel Sambuc cie->cie_daf = _dwarf_read_sleb128(ds->ds_data, off);
241*0a6a1f1dSLionel Sambuc
242*0a6a1f1dSLionel Sambuc /* Return address register. */
243*0a6a1f1dSLionel Sambuc if (cie->cie_version == 1)
244*0a6a1f1dSLionel Sambuc cie->cie_ra = dbg->read(ds->ds_data, off, 1);
245*0a6a1f1dSLionel Sambuc else
246*0a6a1f1dSLionel Sambuc cie->cie_ra = _dwarf_read_uleb128(ds->ds_data, off);
247*0a6a1f1dSLionel Sambuc
248*0a6a1f1dSLionel Sambuc /* Optional CIE augmentation data for .eh_frame section. */
249*0a6a1f1dSLionel Sambuc if (*cie->cie_augment == 'z') {
250*0a6a1f1dSLionel Sambuc cie->cie_auglen = _dwarf_read_uleb128(ds->ds_data, off);
251*0a6a1f1dSLionel Sambuc cie->cie_augdata = ds->ds_data + *off;
252*0a6a1f1dSLionel Sambuc *off += cie->cie_auglen;
253*0a6a1f1dSLionel Sambuc /*
254*0a6a1f1dSLionel Sambuc * XXX Use DW_EH_PE_absptr for default FDE PC start/range,
255*0a6a1f1dSLionel Sambuc * in case _dwarf_frame_parse_lsb_cie_augment fails to
256*0a6a1f1dSLionel Sambuc * find out the real encode.
257*0a6a1f1dSLionel Sambuc */
258*0a6a1f1dSLionel Sambuc cie->cie_fde_encode = DW_EH_PE_absptr;
259*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_parse_lsb_cie_augment(dbg, cie, error);
260*0a6a1f1dSLionel Sambuc if (ret != DW_DLE_NONE)
261*0a6a1f1dSLionel Sambuc return (ret);
262*0a6a1f1dSLionel Sambuc }
263*0a6a1f1dSLionel Sambuc
264*0a6a1f1dSLionel Sambuc /* CIE Initial instructions. */
265*0a6a1f1dSLionel Sambuc cie->cie_initinst = ds->ds_data + *off;
266*0a6a1f1dSLionel Sambuc if (dwarf_size == 4)
267*0a6a1f1dSLionel Sambuc cie->cie_instlen = cie->cie_offset + 4 + length - *off;
268*0a6a1f1dSLionel Sambuc else
269*0a6a1f1dSLionel Sambuc cie->cie_instlen = cie->cie_offset + 12 + length - *off;
270*0a6a1f1dSLionel Sambuc
271*0a6a1f1dSLionel Sambuc *off += cie->cie_instlen;
272*0a6a1f1dSLionel Sambuc
273*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
274*0a6a1f1dSLionel Sambuc printf("cie:\n");
275*0a6a1f1dSLionel Sambuc printf("\tcie_version=%u cie_offset=%ju cie_length=%ju cie_augment=%s"
276*0a6a1f1dSLionel Sambuc " cie_instlen=%ju cie->cie_caf=%ju cie->cie_daf=%jd off=%ju\n",
277*0a6a1f1dSLionel Sambuc cie->cie_version, cie->cie_offset, cie->cie_length,
278*0a6a1f1dSLionel Sambuc (char *)cie->cie_augment, cie->cie_instlen, cie->cie_caf,
279*0a6a1f1dSLionel Sambuc cie->cie_daf, *off);
280*0a6a1f1dSLionel Sambuc #endif
281*0a6a1f1dSLionel Sambuc
282*0a6a1f1dSLionel Sambuc if (ret_cie != NULL)
283*0a6a1f1dSLionel Sambuc *ret_cie = cie;
284*0a6a1f1dSLionel Sambuc
285*0a6a1f1dSLionel Sambuc fs->fs_cielen++;
286*0a6a1f1dSLionel Sambuc
287*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
288*0a6a1f1dSLionel Sambuc }
289*0a6a1f1dSLionel Sambuc
290*0a6a1f1dSLionel Sambuc static int
_dwarf_frame_add_fde(Dwarf_Debug dbg,Dwarf_FrameSec fs,Dwarf_Section * ds,Dwarf_Unsigned * off,int eh_frame,Dwarf_Error * error)291*0a6a1f1dSLionel Sambuc _dwarf_frame_add_fde(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds,
292*0a6a1f1dSLionel Sambuc Dwarf_Unsigned *off, int eh_frame, Dwarf_Error *error)
293*0a6a1f1dSLionel Sambuc {
294*0a6a1f1dSLionel Sambuc Dwarf_Cie cie;
295*0a6a1f1dSLionel Sambuc Dwarf_Fde fde;
296*0a6a1f1dSLionel Sambuc Dwarf_Unsigned cieoff;
297*0a6a1f1dSLionel Sambuc uint64_t length, val;
298*0a6a1f1dSLionel Sambuc int dwarf_size, ret;
299*0a6a1f1dSLionel Sambuc
300*0a6a1f1dSLionel Sambuc if ((fde = calloc(1, sizeof(struct _Dwarf_Fde))) == NULL) {
301*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
302*0a6a1f1dSLionel Sambuc return (DW_DLE_MEMORY);
303*0a6a1f1dSLionel Sambuc }
304*0a6a1f1dSLionel Sambuc STAILQ_INSERT_TAIL(&fs->fs_fdelist, fde, fde_next);
305*0a6a1f1dSLionel Sambuc
306*0a6a1f1dSLionel Sambuc fde->fde_dbg = dbg;
307*0a6a1f1dSLionel Sambuc fde->fde_fs = fs;
308*0a6a1f1dSLionel Sambuc fde->fde_addr = ds->ds_data + *off;
309*0a6a1f1dSLionel Sambuc fde->fde_offset = *off;
310*0a6a1f1dSLionel Sambuc
311*0a6a1f1dSLionel Sambuc length = dbg->read(ds->ds_data, off, 4);
312*0a6a1f1dSLionel Sambuc if (length == 0xffffffff) {
313*0a6a1f1dSLionel Sambuc dwarf_size = 8;
314*0a6a1f1dSLionel Sambuc length = dbg->read(ds->ds_data, off, 8);
315*0a6a1f1dSLionel Sambuc } else
316*0a6a1f1dSLionel Sambuc dwarf_size = 4;
317*0a6a1f1dSLionel Sambuc
318*0a6a1f1dSLionel Sambuc if (length > ds->ds_size - *off) {
319*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
320*0a6a1f1dSLionel Sambuc return (DW_DLE_DEBUG_FRAME_LENGTH_BAD);
321*0a6a1f1dSLionel Sambuc }
322*0a6a1f1dSLionel Sambuc
323*0a6a1f1dSLionel Sambuc fde->fde_length = length;
324*0a6a1f1dSLionel Sambuc
325*0a6a1f1dSLionel Sambuc if (eh_frame) {
326*0a6a1f1dSLionel Sambuc fde->fde_cieoff = dbg->read(ds->ds_data, off, 4);
327*0a6a1f1dSLionel Sambuc cieoff = *off - (4 + fde->fde_cieoff);
328*0a6a1f1dSLionel Sambuc /* This delta should never be 0. */
329*0a6a1f1dSLionel Sambuc if (cieoff == fde->fde_offset) {
330*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_NO_CIE_FOR_FDE);
331*0a6a1f1dSLionel Sambuc return (DW_DLE_NO_CIE_FOR_FDE);
332*0a6a1f1dSLionel Sambuc }
333*0a6a1f1dSLionel Sambuc } else {
334*0a6a1f1dSLionel Sambuc fde->fde_cieoff = dbg->read(ds->ds_data, off, dwarf_size);
335*0a6a1f1dSLionel Sambuc cieoff = fde->fde_cieoff;
336*0a6a1f1dSLionel Sambuc }
337*0a6a1f1dSLionel Sambuc
338*0a6a1f1dSLionel Sambuc if (_dwarf_frame_find_cie(fs, cieoff, &cie) ==
339*0a6a1f1dSLionel Sambuc DW_DLE_NO_ENTRY) {
340*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_add_cie(dbg, fs, ds, &cieoff, &cie,
341*0a6a1f1dSLionel Sambuc error);
342*0a6a1f1dSLionel Sambuc if (ret != DW_DLE_NONE)
343*0a6a1f1dSLionel Sambuc return (ret);
344*0a6a1f1dSLionel Sambuc }
345*0a6a1f1dSLionel Sambuc fde->fde_cie = cie;
346*0a6a1f1dSLionel Sambuc if (eh_frame) {
347*0a6a1f1dSLionel Sambuc /*
348*0a6a1f1dSLionel Sambuc * The FDE PC start/range for .eh_frame is encoded according
349*0a6a1f1dSLionel Sambuc * to the LSB spec's extension to DWARF2.
350*0a6a1f1dSLionel Sambuc */
351*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_read_lsb_encoded(dbg, &val, ds->ds_data,
352*0a6a1f1dSLionel Sambuc off, cie->cie_fde_encode, ds->ds_addr + *off, error);
353*0a6a1f1dSLionel Sambuc if (ret != DW_DLE_NONE)
354*0a6a1f1dSLionel Sambuc return (ret);
355*0a6a1f1dSLionel Sambuc fde->fde_initloc = val;
356*0a6a1f1dSLionel Sambuc /*
357*0a6a1f1dSLionel Sambuc * FDE PC range should not be relative value to anything.
358*0a6a1f1dSLionel Sambuc * So pass 0 for pc value.
359*0a6a1f1dSLionel Sambuc */
360*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_read_lsb_encoded(dbg, &val, ds->ds_data,
361*0a6a1f1dSLionel Sambuc off, cie->cie_fde_encode, 0, error);
362*0a6a1f1dSLionel Sambuc if (ret != DW_DLE_NONE)
363*0a6a1f1dSLionel Sambuc return (ret);
364*0a6a1f1dSLionel Sambuc fde->fde_adrange = val;
365*0a6a1f1dSLionel Sambuc } else {
366*0a6a1f1dSLionel Sambuc fde->fde_initloc = dbg->read(ds->ds_data, off,
367*0a6a1f1dSLionel Sambuc dbg->dbg_pointer_size);
368*0a6a1f1dSLionel Sambuc fde->fde_adrange = dbg->read(ds->ds_data, off,
369*0a6a1f1dSLionel Sambuc dbg->dbg_pointer_size);
370*0a6a1f1dSLionel Sambuc }
371*0a6a1f1dSLionel Sambuc
372*0a6a1f1dSLionel Sambuc /* Optional FDE augmentation data for .eh_frame section. (ignored) */
373*0a6a1f1dSLionel Sambuc if (eh_frame && *cie->cie_augment == 'z') {
374*0a6a1f1dSLionel Sambuc fde->fde_auglen = _dwarf_read_uleb128(ds->ds_data, off);
375*0a6a1f1dSLionel Sambuc fde->fde_augdata = ds->ds_data + *off;
376*0a6a1f1dSLionel Sambuc *off += fde->fde_auglen;
377*0a6a1f1dSLionel Sambuc }
378*0a6a1f1dSLionel Sambuc
379*0a6a1f1dSLionel Sambuc fde->fde_inst = ds->ds_data + *off;
380*0a6a1f1dSLionel Sambuc if (dwarf_size == 4)
381*0a6a1f1dSLionel Sambuc fde->fde_instlen = fde->fde_offset + 4 + length - *off;
382*0a6a1f1dSLionel Sambuc else
383*0a6a1f1dSLionel Sambuc fde->fde_instlen = fde->fde_offset + 12 + length - *off;
384*0a6a1f1dSLionel Sambuc
385*0a6a1f1dSLionel Sambuc *off += fde->fde_instlen;
386*0a6a1f1dSLionel Sambuc
387*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
388*0a6a1f1dSLionel Sambuc printf("fde:");
389*0a6a1f1dSLionel Sambuc if (eh_frame)
390*0a6a1f1dSLionel Sambuc printf("(eh_frame)");
391*0a6a1f1dSLionel Sambuc putchar('\n');
392*0a6a1f1dSLionel Sambuc printf("\tfde_offset=%ju fde_length=%ju fde_cieoff=%ju"
393*0a6a1f1dSLionel Sambuc " fde_instlen=%ju off=%ju\n", fde->fde_offset, fde->fde_length,
394*0a6a1f1dSLionel Sambuc fde->fde_cieoff, fde->fde_instlen, *off);
395*0a6a1f1dSLionel Sambuc #endif
396*0a6a1f1dSLionel Sambuc
397*0a6a1f1dSLionel Sambuc fs->fs_fdelen++;
398*0a6a1f1dSLionel Sambuc
399*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
400*0a6a1f1dSLionel Sambuc }
401*0a6a1f1dSLionel Sambuc
402*0a6a1f1dSLionel Sambuc static void
_dwarf_frame_section_cleanup(Dwarf_FrameSec fs)403*0a6a1f1dSLionel Sambuc _dwarf_frame_section_cleanup(Dwarf_FrameSec fs)
404*0a6a1f1dSLionel Sambuc {
405*0a6a1f1dSLionel Sambuc Dwarf_Cie cie, tcie;
406*0a6a1f1dSLionel Sambuc Dwarf_Fde fde, tfde;
407*0a6a1f1dSLionel Sambuc
408*0a6a1f1dSLionel Sambuc STAILQ_FOREACH_SAFE(cie, &fs->fs_cielist, cie_next, tcie) {
409*0a6a1f1dSLionel Sambuc STAILQ_REMOVE(&fs->fs_cielist, cie, _Dwarf_Cie, cie_next);
410*0a6a1f1dSLionel Sambuc free(cie);
411*0a6a1f1dSLionel Sambuc }
412*0a6a1f1dSLionel Sambuc
413*0a6a1f1dSLionel Sambuc STAILQ_FOREACH_SAFE(fde, &fs->fs_fdelist, fde_next, tfde) {
414*0a6a1f1dSLionel Sambuc STAILQ_REMOVE(&fs->fs_fdelist, fde, _Dwarf_Fde, fde_next);
415*0a6a1f1dSLionel Sambuc free(fde);
416*0a6a1f1dSLionel Sambuc }
417*0a6a1f1dSLionel Sambuc
418*0a6a1f1dSLionel Sambuc if (fs->fs_ciearray != NULL)
419*0a6a1f1dSLionel Sambuc free(fs->fs_ciearray);
420*0a6a1f1dSLionel Sambuc if (fs->fs_fdearray != NULL)
421*0a6a1f1dSLionel Sambuc free(fs->fs_fdearray);
422*0a6a1f1dSLionel Sambuc
423*0a6a1f1dSLionel Sambuc free(fs);
424*0a6a1f1dSLionel Sambuc }
425*0a6a1f1dSLionel Sambuc
426*0a6a1f1dSLionel Sambuc static int
_dwarf_frame_section_init(Dwarf_Debug dbg,Dwarf_FrameSec * frame_sec,Dwarf_Section * ds,int eh_frame,Dwarf_Error * error)427*0a6a1f1dSLionel Sambuc _dwarf_frame_section_init(Dwarf_Debug dbg, Dwarf_FrameSec *frame_sec,
428*0a6a1f1dSLionel Sambuc Dwarf_Section *ds, int eh_frame, Dwarf_Error *error)
429*0a6a1f1dSLionel Sambuc {
430*0a6a1f1dSLionel Sambuc Dwarf_FrameSec fs;
431*0a6a1f1dSLionel Sambuc Dwarf_Cie cie;
432*0a6a1f1dSLionel Sambuc Dwarf_Fde fde;
433*0a6a1f1dSLionel Sambuc uint64_t length, offset, cie_id, entry_off;
434*0a6a1f1dSLionel Sambuc int dwarf_size, i, ret;
435*0a6a1f1dSLionel Sambuc
436*0a6a1f1dSLionel Sambuc assert(frame_sec != NULL);
437*0a6a1f1dSLionel Sambuc assert(*frame_sec == NULL);
438*0a6a1f1dSLionel Sambuc
439*0a6a1f1dSLionel Sambuc if ((fs = calloc(1, sizeof(struct _Dwarf_FrameSec))) == NULL) {
440*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
441*0a6a1f1dSLionel Sambuc return (DW_DLE_MEMORY);
442*0a6a1f1dSLionel Sambuc }
443*0a6a1f1dSLionel Sambuc STAILQ_INIT(&fs->fs_cielist);
444*0a6a1f1dSLionel Sambuc STAILQ_INIT(&fs->fs_fdelist);
445*0a6a1f1dSLionel Sambuc
446*0a6a1f1dSLionel Sambuc offset = 0;
447*0a6a1f1dSLionel Sambuc while (offset < ds->ds_size) {
448*0a6a1f1dSLionel Sambuc entry_off = offset;
449*0a6a1f1dSLionel Sambuc length = dbg->read(ds->ds_data, &offset, 4);
450*0a6a1f1dSLionel Sambuc if (length == 0xffffffff) {
451*0a6a1f1dSLionel Sambuc dwarf_size = 8;
452*0a6a1f1dSLionel Sambuc length = dbg->read(ds->ds_data, &offset, 8);
453*0a6a1f1dSLionel Sambuc } else
454*0a6a1f1dSLionel Sambuc dwarf_size = 4;
455*0a6a1f1dSLionel Sambuc
456*0a6a1f1dSLionel Sambuc if (length > ds->ds_size - offset ||
457*0a6a1f1dSLionel Sambuc (length == 0 && !eh_frame)) {
458*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error,
459*0a6a1f1dSLionel Sambuc DW_DLE_DEBUG_FRAME_LENGTH_BAD);
460*0a6a1f1dSLionel Sambuc return (DW_DLE_DEBUG_FRAME_LENGTH_BAD);
461*0a6a1f1dSLionel Sambuc }
462*0a6a1f1dSLionel Sambuc
463*0a6a1f1dSLionel Sambuc /* Check terminator for .eh_frame */
464*0a6a1f1dSLionel Sambuc if (eh_frame && length == 0)
465*0a6a1f1dSLionel Sambuc break;
466*0a6a1f1dSLionel Sambuc
467*0a6a1f1dSLionel Sambuc cie_id = dbg->read(ds->ds_data, &offset, dwarf_size);
468*0a6a1f1dSLionel Sambuc
469*0a6a1f1dSLionel Sambuc if (eh_frame) {
470*0a6a1f1dSLionel Sambuc /* GNU .eh_frame use CIE id 0. */
471*0a6a1f1dSLionel Sambuc if (cie_id == 0)
472*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_add_cie(dbg, fs, ds,
473*0a6a1f1dSLionel Sambuc &entry_off, NULL, error);
474*0a6a1f1dSLionel Sambuc else
475*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_add_fde(dbg, fs, ds,
476*0a6a1f1dSLionel Sambuc &entry_off, 1, error);
477*0a6a1f1dSLionel Sambuc } else {
478*0a6a1f1dSLionel Sambuc /* .dwarf_frame use CIE id ~0 */
479*0a6a1f1dSLionel Sambuc if ((dwarf_size == 4 && cie_id == ~0U) ||
480*0a6a1f1dSLionel Sambuc (dwarf_size == 8 && cie_id == ~0ULL))
481*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_add_cie(dbg, fs, ds,
482*0a6a1f1dSLionel Sambuc &entry_off, NULL, error);
483*0a6a1f1dSLionel Sambuc else
484*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_add_fde(dbg, fs, ds,
485*0a6a1f1dSLionel Sambuc &entry_off, 0, error);
486*0a6a1f1dSLionel Sambuc }
487*0a6a1f1dSLionel Sambuc
488*0a6a1f1dSLionel Sambuc if (ret != DW_DLE_NONE)
489*0a6a1f1dSLionel Sambuc goto fail_cleanup;
490*0a6a1f1dSLionel Sambuc
491*0a6a1f1dSLionel Sambuc offset = entry_off;
492*0a6a1f1dSLionel Sambuc }
493*0a6a1f1dSLionel Sambuc
494*0a6a1f1dSLionel Sambuc /* Create CIE array. */
495*0a6a1f1dSLionel Sambuc if (fs->fs_cielen > 0) {
496*0a6a1f1dSLionel Sambuc if ((fs->fs_ciearray = malloc(sizeof(Dwarf_Cie) *
497*0a6a1f1dSLionel Sambuc fs->fs_cielen)) == NULL) {
498*0a6a1f1dSLionel Sambuc ret = DW_DLE_MEMORY;
499*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, ret);
500*0a6a1f1dSLionel Sambuc goto fail_cleanup;
501*0a6a1f1dSLionel Sambuc }
502*0a6a1f1dSLionel Sambuc i = 0;
503*0a6a1f1dSLionel Sambuc STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) {
504*0a6a1f1dSLionel Sambuc fs->fs_ciearray[i++] = cie;
505*0a6a1f1dSLionel Sambuc }
506*0a6a1f1dSLionel Sambuc assert((Dwarf_Unsigned)i == fs->fs_cielen);
507*0a6a1f1dSLionel Sambuc }
508*0a6a1f1dSLionel Sambuc
509*0a6a1f1dSLionel Sambuc /* Create FDE array. */
510*0a6a1f1dSLionel Sambuc if (fs->fs_fdelen > 0) {
511*0a6a1f1dSLionel Sambuc if ((fs->fs_fdearray = malloc(sizeof(Dwarf_Fde) *
512*0a6a1f1dSLionel Sambuc fs->fs_fdelen)) == NULL) {
513*0a6a1f1dSLionel Sambuc ret = DW_DLE_MEMORY;
514*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, ret);
515*0a6a1f1dSLionel Sambuc goto fail_cleanup;
516*0a6a1f1dSLionel Sambuc }
517*0a6a1f1dSLionel Sambuc i = 0;
518*0a6a1f1dSLionel Sambuc STAILQ_FOREACH(fde, &fs->fs_fdelist, fde_next) {
519*0a6a1f1dSLionel Sambuc fs->fs_fdearray[i++] = fde;
520*0a6a1f1dSLionel Sambuc }
521*0a6a1f1dSLionel Sambuc assert((Dwarf_Unsigned)i == fs->fs_fdelen);
522*0a6a1f1dSLionel Sambuc }
523*0a6a1f1dSLionel Sambuc
524*0a6a1f1dSLionel Sambuc *frame_sec = fs;
525*0a6a1f1dSLionel Sambuc
526*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
527*0a6a1f1dSLionel Sambuc
528*0a6a1f1dSLionel Sambuc fail_cleanup:
529*0a6a1f1dSLionel Sambuc
530*0a6a1f1dSLionel Sambuc _dwarf_frame_section_cleanup(fs);
531*0a6a1f1dSLionel Sambuc
532*0a6a1f1dSLionel Sambuc return (ret);
533*0a6a1f1dSLionel Sambuc }
534*0a6a1f1dSLionel Sambuc
535*0a6a1f1dSLionel Sambuc static int
_dwarf_frame_run_inst(Dwarf_Debug dbg,Dwarf_Regtable3 * rt,uint8_t * insts,Dwarf_Unsigned len,Dwarf_Unsigned caf,Dwarf_Signed daf,Dwarf_Addr pc,Dwarf_Addr pc_req,Dwarf_Addr * row_pc,Dwarf_Error * error)536*0a6a1f1dSLionel Sambuc _dwarf_frame_run_inst(Dwarf_Debug dbg, Dwarf_Regtable3 *rt, uint8_t *insts,
537*0a6a1f1dSLionel Sambuc Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf, Dwarf_Addr pc,
538*0a6a1f1dSLionel Sambuc Dwarf_Addr pc_req, Dwarf_Addr *row_pc, Dwarf_Error *error)
539*0a6a1f1dSLionel Sambuc {
540*0a6a1f1dSLionel Sambuc Dwarf_Regtable3 *init_rt, *saved_rt;
541*0a6a1f1dSLionel Sambuc uint8_t *p, *pe;
542*0a6a1f1dSLionel Sambuc uint8_t high2, low6;
543*0a6a1f1dSLionel Sambuc uint64_t reg, reg2, uoff, soff;
544*0a6a1f1dSLionel Sambuc int ret;
545*0a6a1f1dSLionel Sambuc
546*0a6a1f1dSLionel Sambuc #define CFA rt->rt3_cfa_rule
547*0a6a1f1dSLionel Sambuc #define INITCFA init_rt->rt3_cfa_rule
548*0a6a1f1dSLionel Sambuc #define RL rt->rt3_rules
549*0a6a1f1dSLionel Sambuc #define INITRL init_rt->rt3_rules
550*0a6a1f1dSLionel Sambuc
551*0a6a1f1dSLionel Sambuc #define CHECK_TABLE_SIZE(x) \
552*0a6a1f1dSLionel Sambuc do { \
553*0a6a1f1dSLionel Sambuc if ((x) >= rt->rt3_reg_table_size) { \
554*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, \
555*0a6a1f1dSLionel Sambuc DW_DLE_DF_REG_NUM_TOO_HIGH); \
556*0a6a1f1dSLionel Sambuc ret = DW_DLE_DF_REG_NUM_TOO_HIGH; \
557*0a6a1f1dSLionel Sambuc goto program_done; \
558*0a6a1f1dSLionel Sambuc } \
559*0a6a1f1dSLionel Sambuc } while(0)
560*0a6a1f1dSLionel Sambuc
561*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
562*0a6a1f1dSLionel Sambuc printf("frame_run_inst: (caf=%ju, daf=%jd)\n", caf, daf);
563*0a6a1f1dSLionel Sambuc #endif
564*0a6a1f1dSLionel Sambuc
565*0a6a1f1dSLionel Sambuc ret = DW_DLE_NONE;
566*0a6a1f1dSLionel Sambuc init_rt = saved_rt = NULL;
567*0a6a1f1dSLionel Sambuc *row_pc = pc;
568*0a6a1f1dSLionel Sambuc
569*0a6a1f1dSLionel Sambuc /* Save a copy of the table as initial state. */
570*0a6a1f1dSLionel Sambuc _dwarf_frame_regtable_copy(dbg, &init_rt, rt, error);
571*0a6a1f1dSLionel Sambuc
572*0a6a1f1dSLionel Sambuc p = insts;
573*0a6a1f1dSLionel Sambuc pe = p + len;
574*0a6a1f1dSLionel Sambuc
575*0a6a1f1dSLionel Sambuc while (p < pe) {
576*0a6a1f1dSLionel Sambuc
577*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
578*0a6a1f1dSLionel Sambuc printf("p=%p pe=%p pc=%#jx pc_req=%#jx\n", p, pe, pc, pc_req);
579*0a6a1f1dSLionel Sambuc #endif
580*0a6a1f1dSLionel Sambuc
581*0a6a1f1dSLionel Sambuc if (*p == DW_CFA_nop) {
582*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
583*0a6a1f1dSLionel Sambuc printf("DW_CFA_nop\n");
584*0a6a1f1dSLionel Sambuc #endif
585*0a6a1f1dSLionel Sambuc p++;
586*0a6a1f1dSLionel Sambuc continue;
587*0a6a1f1dSLionel Sambuc }
588*0a6a1f1dSLionel Sambuc
589*0a6a1f1dSLionel Sambuc high2 = *p & 0xc0;
590*0a6a1f1dSLionel Sambuc low6 = *p & 0x3f;
591*0a6a1f1dSLionel Sambuc p++;
592*0a6a1f1dSLionel Sambuc
593*0a6a1f1dSLionel Sambuc if (high2 > 0) {
594*0a6a1f1dSLionel Sambuc switch (high2) {
595*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc:
596*0a6a1f1dSLionel Sambuc pc += low6 * caf;
597*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
598*0a6a1f1dSLionel Sambuc printf("DW_CFA_advance_loc(%#jx(%u))\n", pc,
599*0a6a1f1dSLionel Sambuc low6);
600*0a6a1f1dSLionel Sambuc #endif
601*0a6a1f1dSLionel Sambuc if (pc_req < pc)
602*0a6a1f1dSLionel Sambuc goto program_done;
603*0a6a1f1dSLionel Sambuc break;
604*0a6a1f1dSLionel Sambuc case DW_CFA_offset:
605*0a6a1f1dSLionel Sambuc *row_pc = pc;
606*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(low6);
607*0a6a1f1dSLionel Sambuc RL[low6].dw_offset_relevant = 1;
608*0a6a1f1dSLionel Sambuc RL[low6].dw_value_type = DW_EXPR_OFFSET;
609*0a6a1f1dSLionel Sambuc RL[low6].dw_regnum = dbg->dbg_frame_cfa_value;
610*0a6a1f1dSLionel Sambuc RL[low6].dw_offset_or_block_len =
611*0a6a1f1dSLionel Sambuc _dwarf_decode_uleb128(&p) * daf;
612*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
613*0a6a1f1dSLionel Sambuc printf("DW_CFA_offset(%jd)\n",
614*0a6a1f1dSLionel Sambuc RL[low6].dw_offset_or_block_len);
615*0a6a1f1dSLionel Sambuc #endif
616*0a6a1f1dSLionel Sambuc break;
617*0a6a1f1dSLionel Sambuc case DW_CFA_restore:
618*0a6a1f1dSLionel Sambuc *row_pc = pc;
619*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(low6);
620*0a6a1f1dSLionel Sambuc memcpy(&RL[low6], &INITRL[low6],
621*0a6a1f1dSLionel Sambuc sizeof(Dwarf_Regtable_Entry3));
622*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
623*0a6a1f1dSLionel Sambuc printf("DW_CFA_restore(%u)\n", low6);
624*0a6a1f1dSLionel Sambuc #endif
625*0a6a1f1dSLionel Sambuc break;
626*0a6a1f1dSLionel Sambuc default:
627*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error,
628*0a6a1f1dSLionel Sambuc DW_DLE_FRAME_INSTR_EXEC_ERROR);
629*0a6a1f1dSLionel Sambuc ret = DW_DLE_FRAME_INSTR_EXEC_ERROR;
630*0a6a1f1dSLionel Sambuc goto program_done;
631*0a6a1f1dSLionel Sambuc }
632*0a6a1f1dSLionel Sambuc
633*0a6a1f1dSLionel Sambuc continue;
634*0a6a1f1dSLionel Sambuc }
635*0a6a1f1dSLionel Sambuc
636*0a6a1f1dSLionel Sambuc switch (low6) {
637*0a6a1f1dSLionel Sambuc case DW_CFA_set_loc:
638*0a6a1f1dSLionel Sambuc pc = dbg->decode(&p, dbg->dbg_pointer_size);
639*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
640*0a6a1f1dSLionel Sambuc printf("DW_CFA_set_loc(pc=%#jx)\n", pc);
641*0a6a1f1dSLionel Sambuc #endif
642*0a6a1f1dSLionel Sambuc if (pc_req < pc)
643*0a6a1f1dSLionel Sambuc goto program_done;
644*0a6a1f1dSLionel Sambuc break;
645*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc1:
646*0a6a1f1dSLionel Sambuc pc += dbg->decode(&p, 1) * caf;
647*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
648*0a6a1f1dSLionel Sambuc printf("DW_CFA_set_loc1(pc=%#jx)\n", pc);
649*0a6a1f1dSLionel Sambuc #endif
650*0a6a1f1dSLionel Sambuc if (pc_req < pc)
651*0a6a1f1dSLionel Sambuc goto program_done;
652*0a6a1f1dSLionel Sambuc break;
653*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc2:
654*0a6a1f1dSLionel Sambuc pc += dbg->decode(&p, 2) * caf;
655*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
656*0a6a1f1dSLionel Sambuc printf("DW_CFA_set_loc2(pc=%#jx)\n", pc);
657*0a6a1f1dSLionel Sambuc #endif
658*0a6a1f1dSLionel Sambuc if (pc_req < pc)
659*0a6a1f1dSLionel Sambuc goto program_done;
660*0a6a1f1dSLionel Sambuc break;
661*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc4:
662*0a6a1f1dSLionel Sambuc pc += dbg->decode(&p, 4) * caf;
663*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
664*0a6a1f1dSLionel Sambuc printf("DW_CFA_set_loc4(pc=%#jx)\n", pc);
665*0a6a1f1dSLionel Sambuc #endif
666*0a6a1f1dSLionel Sambuc if (pc_req < pc)
667*0a6a1f1dSLionel Sambuc goto program_done;
668*0a6a1f1dSLionel Sambuc break;
669*0a6a1f1dSLionel Sambuc case DW_CFA_offset_extended:
670*0a6a1f1dSLionel Sambuc *row_pc = pc;
671*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
672*0a6a1f1dSLionel Sambuc uoff = _dwarf_decode_uleb128(&p);
673*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(reg);
674*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_relevant = 1;
675*0a6a1f1dSLionel Sambuc RL[reg].dw_value_type = DW_EXPR_OFFSET;
676*0a6a1f1dSLionel Sambuc RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
677*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_or_block_len = uoff * daf;
678*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
679*0a6a1f1dSLionel Sambuc printf("DW_CFA_offset_extended(reg=%ju,uoff=%ju)\n",
680*0a6a1f1dSLionel Sambuc reg, uoff);
681*0a6a1f1dSLionel Sambuc #endif
682*0a6a1f1dSLionel Sambuc break;
683*0a6a1f1dSLionel Sambuc case DW_CFA_restore_extended:
684*0a6a1f1dSLionel Sambuc *row_pc = pc;
685*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
686*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(reg);
687*0a6a1f1dSLionel Sambuc memcpy(&RL[reg], &INITRL[reg],
688*0a6a1f1dSLionel Sambuc sizeof(Dwarf_Regtable_Entry3));
689*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
690*0a6a1f1dSLionel Sambuc printf("DW_CFA_restore_extended(%ju)\n", reg);
691*0a6a1f1dSLionel Sambuc #endif
692*0a6a1f1dSLionel Sambuc break;
693*0a6a1f1dSLionel Sambuc case DW_CFA_undefined:
694*0a6a1f1dSLionel Sambuc *row_pc = pc;
695*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
696*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(reg);
697*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_relevant = 0;
698*0a6a1f1dSLionel Sambuc RL[reg].dw_regnum = dbg->dbg_frame_undefined_value;
699*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
700*0a6a1f1dSLionel Sambuc printf("DW_CFA_undefined(%ju)\n", reg);
701*0a6a1f1dSLionel Sambuc #endif
702*0a6a1f1dSLionel Sambuc break;
703*0a6a1f1dSLionel Sambuc case DW_CFA_same_value:
704*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
705*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(reg);
706*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_relevant = 0;
707*0a6a1f1dSLionel Sambuc RL[reg].dw_regnum = dbg->dbg_frame_same_value;
708*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
709*0a6a1f1dSLionel Sambuc printf("DW_CFA_same_value(%ju)\n", reg);
710*0a6a1f1dSLionel Sambuc #endif
711*0a6a1f1dSLionel Sambuc break;
712*0a6a1f1dSLionel Sambuc case DW_CFA_register:
713*0a6a1f1dSLionel Sambuc *row_pc = pc;
714*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
715*0a6a1f1dSLionel Sambuc reg2 = _dwarf_decode_uleb128(&p);
716*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(reg);
717*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_relevant = 0;
718*0a6a1f1dSLionel Sambuc RL[reg].dw_regnum = reg2;
719*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
720*0a6a1f1dSLionel Sambuc printf("DW_CFA_register(reg=%ju,reg2=%ju)\n", reg,
721*0a6a1f1dSLionel Sambuc reg2);
722*0a6a1f1dSLionel Sambuc #endif
723*0a6a1f1dSLionel Sambuc break;
724*0a6a1f1dSLionel Sambuc case DW_CFA_remember_state:
725*0a6a1f1dSLionel Sambuc _dwarf_frame_regtable_copy(dbg, &saved_rt, rt, error);
726*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
727*0a6a1f1dSLionel Sambuc printf("DW_CFA_remember_state\n");
728*0a6a1f1dSLionel Sambuc #endif
729*0a6a1f1dSLionel Sambuc break;
730*0a6a1f1dSLionel Sambuc case DW_CFA_restore_state:
731*0a6a1f1dSLionel Sambuc *row_pc = pc;
732*0a6a1f1dSLionel Sambuc _dwarf_frame_regtable_copy(dbg, &rt, saved_rt, error);
733*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
734*0a6a1f1dSLionel Sambuc printf("DW_CFA_restore_state\n");
735*0a6a1f1dSLionel Sambuc #endif
736*0a6a1f1dSLionel Sambuc break;
737*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa:
738*0a6a1f1dSLionel Sambuc *row_pc = pc;
739*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
740*0a6a1f1dSLionel Sambuc uoff = _dwarf_decode_uleb128(&p);
741*0a6a1f1dSLionel Sambuc CFA.dw_offset_relevant = 1;
742*0a6a1f1dSLionel Sambuc CFA.dw_value_type = DW_EXPR_OFFSET;
743*0a6a1f1dSLionel Sambuc CFA.dw_regnum = reg;
744*0a6a1f1dSLionel Sambuc CFA.dw_offset_or_block_len = uoff;
745*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
746*0a6a1f1dSLionel Sambuc printf("DW_CFA_def_cfa(reg=%ju,uoff=%ju)\n", reg, uoff);
747*0a6a1f1dSLionel Sambuc #endif
748*0a6a1f1dSLionel Sambuc break;
749*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_register:
750*0a6a1f1dSLionel Sambuc *row_pc = pc;
751*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
752*0a6a1f1dSLionel Sambuc CFA.dw_regnum = reg;
753*0a6a1f1dSLionel Sambuc /*
754*0a6a1f1dSLionel Sambuc * Note that DW_CFA_def_cfa_register change the CFA
755*0a6a1f1dSLionel Sambuc * rule register while keep the old offset. So we
756*0a6a1f1dSLionel Sambuc * should not touch the CFA.dw_offset_relevant flag
757*0a6a1f1dSLionel Sambuc * here.
758*0a6a1f1dSLionel Sambuc */
759*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
760*0a6a1f1dSLionel Sambuc printf("DW_CFA_def_cfa_register(%ju)\n", reg);
761*0a6a1f1dSLionel Sambuc #endif
762*0a6a1f1dSLionel Sambuc break;
763*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_offset:
764*0a6a1f1dSLionel Sambuc *row_pc = pc;
765*0a6a1f1dSLionel Sambuc uoff = _dwarf_decode_uleb128(&p);
766*0a6a1f1dSLionel Sambuc CFA.dw_offset_relevant = 1;
767*0a6a1f1dSLionel Sambuc CFA.dw_value_type = DW_EXPR_OFFSET;
768*0a6a1f1dSLionel Sambuc CFA.dw_offset_or_block_len = uoff;
769*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
770*0a6a1f1dSLionel Sambuc printf("DW_CFA_def_cfa_offset(%ju)\n", uoff);
771*0a6a1f1dSLionel Sambuc #endif
772*0a6a1f1dSLionel Sambuc break;
773*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_expression:
774*0a6a1f1dSLionel Sambuc *row_pc = pc;
775*0a6a1f1dSLionel Sambuc CFA.dw_offset_relevant = 0;
776*0a6a1f1dSLionel Sambuc CFA.dw_value_type = DW_EXPR_EXPRESSION;
777*0a6a1f1dSLionel Sambuc CFA.dw_offset_or_block_len = _dwarf_decode_uleb128(&p);
778*0a6a1f1dSLionel Sambuc CFA.dw_block_ptr = p;
779*0a6a1f1dSLionel Sambuc p += CFA.dw_offset_or_block_len;
780*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
781*0a6a1f1dSLionel Sambuc printf("DW_CFA_def_cfa_expression\n");
782*0a6a1f1dSLionel Sambuc #endif
783*0a6a1f1dSLionel Sambuc break;
784*0a6a1f1dSLionel Sambuc case DW_CFA_expression:
785*0a6a1f1dSLionel Sambuc *row_pc = pc;
786*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
787*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(reg);
788*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_relevant = 0;
789*0a6a1f1dSLionel Sambuc RL[reg].dw_value_type = DW_EXPR_EXPRESSION;
790*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_or_block_len =
791*0a6a1f1dSLionel Sambuc _dwarf_decode_uleb128(&p);
792*0a6a1f1dSLionel Sambuc RL[reg].dw_block_ptr = p;
793*0a6a1f1dSLionel Sambuc p += RL[reg].dw_offset_or_block_len;
794*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
795*0a6a1f1dSLionel Sambuc printf("DW_CFA_expression\n");
796*0a6a1f1dSLionel Sambuc #endif
797*0a6a1f1dSLionel Sambuc break;
798*0a6a1f1dSLionel Sambuc case DW_CFA_offset_extended_sf:
799*0a6a1f1dSLionel Sambuc *row_pc = pc;
800*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
801*0a6a1f1dSLionel Sambuc soff = _dwarf_decode_sleb128(&p);
802*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(reg);
803*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_relevant = 1;
804*0a6a1f1dSLionel Sambuc RL[reg].dw_value_type = DW_EXPR_OFFSET;
805*0a6a1f1dSLionel Sambuc RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
806*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_or_block_len = soff * daf;
807*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
808*0a6a1f1dSLionel Sambuc printf("DW_CFA_offset_extended_sf(reg=%ju,soff=%jd)\n",
809*0a6a1f1dSLionel Sambuc reg, soff);
810*0a6a1f1dSLionel Sambuc #endif
811*0a6a1f1dSLionel Sambuc break;
812*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_sf:
813*0a6a1f1dSLionel Sambuc *row_pc = pc;
814*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
815*0a6a1f1dSLionel Sambuc soff = _dwarf_decode_sleb128(&p);
816*0a6a1f1dSLionel Sambuc CFA.dw_offset_relevant = 1;
817*0a6a1f1dSLionel Sambuc CFA.dw_value_type = DW_EXPR_OFFSET;
818*0a6a1f1dSLionel Sambuc CFA.dw_regnum = reg;
819*0a6a1f1dSLionel Sambuc CFA.dw_offset_or_block_len = soff * daf;
820*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
821*0a6a1f1dSLionel Sambuc printf("DW_CFA_def_cfa_sf(reg=%ju,soff=%jd)\n", reg,
822*0a6a1f1dSLionel Sambuc soff);
823*0a6a1f1dSLionel Sambuc #endif
824*0a6a1f1dSLionel Sambuc break;
825*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_offset_sf:
826*0a6a1f1dSLionel Sambuc *row_pc = pc;
827*0a6a1f1dSLionel Sambuc soff = _dwarf_decode_sleb128(&p);
828*0a6a1f1dSLionel Sambuc CFA.dw_offset_relevant = 1;
829*0a6a1f1dSLionel Sambuc CFA.dw_value_type = DW_EXPR_OFFSET;
830*0a6a1f1dSLionel Sambuc CFA.dw_offset_or_block_len = soff * daf;
831*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
832*0a6a1f1dSLionel Sambuc printf("DW_CFA_def_cfa_offset_sf(soff=%jd)\n", soff);
833*0a6a1f1dSLionel Sambuc #endif
834*0a6a1f1dSLionel Sambuc break;
835*0a6a1f1dSLionel Sambuc case DW_CFA_val_offset:
836*0a6a1f1dSLionel Sambuc *row_pc = pc;
837*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
838*0a6a1f1dSLionel Sambuc uoff = _dwarf_decode_uleb128(&p);
839*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(reg);
840*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_relevant = 1;
841*0a6a1f1dSLionel Sambuc RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET;
842*0a6a1f1dSLionel Sambuc RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
843*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_or_block_len = uoff * daf;
844*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
845*0a6a1f1dSLionel Sambuc printf("DW_CFA_val_offset(reg=%ju,uoff=%ju)\n", reg,
846*0a6a1f1dSLionel Sambuc uoff);
847*0a6a1f1dSLionel Sambuc #endif
848*0a6a1f1dSLionel Sambuc break;
849*0a6a1f1dSLionel Sambuc case DW_CFA_val_offset_sf:
850*0a6a1f1dSLionel Sambuc *row_pc = pc;
851*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
852*0a6a1f1dSLionel Sambuc soff = _dwarf_decode_sleb128(&p);
853*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(reg);
854*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_relevant = 1;
855*0a6a1f1dSLionel Sambuc RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET;
856*0a6a1f1dSLionel Sambuc RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
857*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_or_block_len = soff * daf;
858*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
859*0a6a1f1dSLionel Sambuc printf("DW_CFA_val_offset_sf(reg=%ju,soff=%jd)\n", reg,
860*0a6a1f1dSLionel Sambuc soff);
861*0a6a1f1dSLionel Sambuc #endif
862*0a6a1f1dSLionel Sambuc break;
863*0a6a1f1dSLionel Sambuc case DW_CFA_val_expression:
864*0a6a1f1dSLionel Sambuc *row_pc = pc;
865*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
866*0a6a1f1dSLionel Sambuc CHECK_TABLE_SIZE(reg);
867*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_relevant = 0;
868*0a6a1f1dSLionel Sambuc RL[reg].dw_value_type = DW_EXPR_VAL_EXPRESSION;
869*0a6a1f1dSLionel Sambuc RL[reg].dw_offset_or_block_len =
870*0a6a1f1dSLionel Sambuc _dwarf_decode_uleb128(&p);
871*0a6a1f1dSLionel Sambuc RL[reg].dw_block_ptr = p;
872*0a6a1f1dSLionel Sambuc p += RL[reg].dw_offset_or_block_len;
873*0a6a1f1dSLionel Sambuc #ifdef FRAME_DEBUG
874*0a6a1f1dSLionel Sambuc printf("DW_CFA_val_expression\n");
875*0a6a1f1dSLionel Sambuc #endif
876*0a6a1f1dSLionel Sambuc break;
877*0a6a1f1dSLionel Sambuc default:
878*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error,
879*0a6a1f1dSLionel Sambuc DW_DLE_FRAME_INSTR_EXEC_ERROR);
880*0a6a1f1dSLionel Sambuc ret = DW_DLE_FRAME_INSTR_EXEC_ERROR;
881*0a6a1f1dSLionel Sambuc goto program_done;
882*0a6a1f1dSLionel Sambuc }
883*0a6a1f1dSLionel Sambuc }
884*0a6a1f1dSLionel Sambuc
885*0a6a1f1dSLionel Sambuc program_done:
886*0a6a1f1dSLionel Sambuc
887*0a6a1f1dSLionel Sambuc free(init_rt->rt3_rules);
888*0a6a1f1dSLionel Sambuc free(init_rt);
889*0a6a1f1dSLionel Sambuc if (saved_rt) {
890*0a6a1f1dSLionel Sambuc free(saved_rt->rt3_rules);
891*0a6a1f1dSLionel Sambuc free(saved_rt);
892*0a6a1f1dSLionel Sambuc }
893*0a6a1f1dSLionel Sambuc
894*0a6a1f1dSLionel Sambuc return (ret);
895*0a6a1f1dSLionel Sambuc
896*0a6a1f1dSLionel Sambuc #undef CFA
897*0a6a1f1dSLionel Sambuc #undef INITCFA
898*0a6a1f1dSLionel Sambuc #undef RL
899*0a6a1f1dSLionel Sambuc #undef INITRL
900*0a6a1f1dSLionel Sambuc #undef CHECK_TABLE_SIZE
901*0a6a1f1dSLionel Sambuc }
902*0a6a1f1dSLionel Sambuc
903*0a6a1f1dSLionel Sambuc static int
_dwarf_frame_convert_inst(Dwarf_Debug dbg,uint8_t * insts,Dwarf_Unsigned len,Dwarf_Unsigned * count,Dwarf_Frame_Op * fop,Dwarf_Frame_Op3 * fop3,Dwarf_Error * error)904*0a6a1f1dSLionel Sambuc _dwarf_frame_convert_inst(Dwarf_Debug dbg, uint8_t *insts, Dwarf_Unsigned len,
905*0a6a1f1dSLionel Sambuc Dwarf_Unsigned *count, Dwarf_Frame_Op *fop, Dwarf_Frame_Op3 *fop3,
906*0a6a1f1dSLionel Sambuc Dwarf_Error *error)
907*0a6a1f1dSLionel Sambuc {
908*0a6a1f1dSLionel Sambuc uint8_t *p, *pe;
909*0a6a1f1dSLionel Sambuc uint8_t high2, low6;
910*0a6a1f1dSLionel Sambuc uint64_t reg, reg2, uoff, soff, blen;
911*0a6a1f1dSLionel Sambuc int ret;
912*0a6a1f1dSLionel Sambuc
913*0a6a1f1dSLionel Sambuc #define SET_BASE_OP(x) \
914*0a6a1f1dSLionel Sambuc do { \
915*0a6a1f1dSLionel Sambuc if (fop != NULL) \
916*0a6a1f1dSLionel Sambuc fop[*count].fp_base_op = (x) >> 6; \
917*0a6a1f1dSLionel Sambuc if (fop3 != NULL) \
918*0a6a1f1dSLionel Sambuc fop3[*count].fp_base_op = (x) >> 6; \
919*0a6a1f1dSLionel Sambuc } while(0)
920*0a6a1f1dSLionel Sambuc
921*0a6a1f1dSLionel Sambuc #define SET_EXTENDED_OP(x) \
922*0a6a1f1dSLionel Sambuc do { \
923*0a6a1f1dSLionel Sambuc if (fop != NULL) \
924*0a6a1f1dSLionel Sambuc fop[*count].fp_extended_op = (x); \
925*0a6a1f1dSLionel Sambuc if (fop3 != NULL) \
926*0a6a1f1dSLionel Sambuc fop3[*count].fp_extended_op = (x); \
927*0a6a1f1dSLionel Sambuc } while(0)
928*0a6a1f1dSLionel Sambuc
929*0a6a1f1dSLionel Sambuc #define SET_REGISTER(x) \
930*0a6a1f1dSLionel Sambuc do { \
931*0a6a1f1dSLionel Sambuc if (fop != NULL) \
932*0a6a1f1dSLionel Sambuc fop[*count].fp_register = (x); \
933*0a6a1f1dSLionel Sambuc if (fop3 != NULL) \
934*0a6a1f1dSLionel Sambuc fop3[*count].fp_register = (x); \
935*0a6a1f1dSLionel Sambuc } while(0)
936*0a6a1f1dSLionel Sambuc
937*0a6a1f1dSLionel Sambuc #define SET_OFFSET(x) \
938*0a6a1f1dSLionel Sambuc do { \
939*0a6a1f1dSLionel Sambuc if (fop != NULL) \
940*0a6a1f1dSLionel Sambuc fop[*count].fp_offset = (x); \
941*0a6a1f1dSLionel Sambuc if (fop3 != NULL) \
942*0a6a1f1dSLionel Sambuc fop3[*count].fp_offset_or_block_len = \
943*0a6a1f1dSLionel Sambuc (x); \
944*0a6a1f1dSLionel Sambuc } while(0)
945*0a6a1f1dSLionel Sambuc
946*0a6a1f1dSLionel Sambuc #define SET_INSTR_OFFSET(x) \
947*0a6a1f1dSLionel Sambuc do { \
948*0a6a1f1dSLionel Sambuc if (fop != NULL) \
949*0a6a1f1dSLionel Sambuc fop[*count].fp_instr_offset = (x); \
950*0a6a1f1dSLionel Sambuc if (fop3 != NULL) \
951*0a6a1f1dSLionel Sambuc fop3[*count].fp_instr_offset = (x); \
952*0a6a1f1dSLionel Sambuc } while(0)
953*0a6a1f1dSLionel Sambuc
954*0a6a1f1dSLionel Sambuc #define SET_BLOCK_LEN(x) \
955*0a6a1f1dSLionel Sambuc do { \
956*0a6a1f1dSLionel Sambuc if (fop3 != NULL) \
957*0a6a1f1dSLionel Sambuc fop3[*count].fp_offset_or_block_len = \
958*0a6a1f1dSLionel Sambuc (x); \
959*0a6a1f1dSLionel Sambuc } while(0)
960*0a6a1f1dSLionel Sambuc
961*0a6a1f1dSLionel Sambuc #define SET_EXPR_BLOCK(addr, len) \
962*0a6a1f1dSLionel Sambuc do { \
963*0a6a1f1dSLionel Sambuc if (fop3 != NULL) { \
964*0a6a1f1dSLionel Sambuc fop3[*count].fp_expr_block = \
965*0a6a1f1dSLionel Sambuc malloc((size_t) (len)); \
966*0a6a1f1dSLionel Sambuc if (fop3[*count].fp_expr_block == NULL) { \
967*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, \
968*0a6a1f1dSLionel Sambuc DW_DLE_MEMORY); \
969*0a6a1f1dSLionel Sambuc return (DW_DLE_MEMORY); \
970*0a6a1f1dSLionel Sambuc } \
971*0a6a1f1dSLionel Sambuc memcpy(&fop3[*count].fp_expr_block, \
972*0a6a1f1dSLionel Sambuc (addr), (len)); \
973*0a6a1f1dSLionel Sambuc } \
974*0a6a1f1dSLionel Sambuc } while(0)
975*0a6a1f1dSLionel Sambuc
976*0a6a1f1dSLionel Sambuc ret = DW_DLE_NONE;
977*0a6a1f1dSLionel Sambuc *count = 0;
978*0a6a1f1dSLionel Sambuc
979*0a6a1f1dSLionel Sambuc p = insts;
980*0a6a1f1dSLionel Sambuc pe = p + len;
981*0a6a1f1dSLionel Sambuc
982*0a6a1f1dSLionel Sambuc while (p < pe) {
983*0a6a1f1dSLionel Sambuc
984*0a6a1f1dSLionel Sambuc SET_INSTR_OFFSET(p - insts);
985*0a6a1f1dSLionel Sambuc
986*0a6a1f1dSLionel Sambuc if (*p == DW_CFA_nop) {
987*0a6a1f1dSLionel Sambuc p++;
988*0a6a1f1dSLionel Sambuc (*count)++;
989*0a6a1f1dSLionel Sambuc continue;
990*0a6a1f1dSLionel Sambuc }
991*0a6a1f1dSLionel Sambuc
992*0a6a1f1dSLionel Sambuc high2 = *p & 0xc0;
993*0a6a1f1dSLionel Sambuc low6 = *p & 0x3f;
994*0a6a1f1dSLionel Sambuc p++;
995*0a6a1f1dSLionel Sambuc
996*0a6a1f1dSLionel Sambuc if (high2 > 0) {
997*0a6a1f1dSLionel Sambuc switch (high2) {
998*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc:
999*0a6a1f1dSLionel Sambuc SET_BASE_OP(high2);
1000*0a6a1f1dSLionel Sambuc SET_OFFSET(low6);
1001*0a6a1f1dSLionel Sambuc break;
1002*0a6a1f1dSLionel Sambuc case DW_CFA_offset:
1003*0a6a1f1dSLionel Sambuc SET_BASE_OP(high2);
1004*0a6a1f1dSLionel Sambuc SET_REGISTER(low6);
1005*0a6a1f1dSLionel Sambuc uoff = _dwarf_decode_uleb128(&p);
1006*0a6a1f1dSLionel Sambuc SET_OFFSET(uoff);
1007*0a6a1f1dSLionel Sambuc break;
1008*0a6a1f1dSLionel Sambuc case DW_CFA_restore:
1009*0a6a1f1dSLionel Sambuc SET_BASE_OP(high2);
1010*0a6a1f1dSLionel Sambuc SET_REGISTER(low6);
1011*0a6a1f1dSLionel Sambuc break;
1012*0a6a1f1dSLionel Sambuc default:
1013*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error,
1014*0a6a1f1dSLionel Sambuc DW_DLE_FRAME_INSTR_EXEC_ERROR);
1015*0a6a1f1dSLionel Sambuc return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1016*0a6a1f1dSLionel Sambuc }
1017*0a6a1f1dSLionel Sambuc
1018*0a6a1f1dSLionel Sambuc (*count)++;
1019*0a6a1f1dSLionel Sambuc continue;
1020*0a6a1f1dSLionel Sambuc }
1021*0a6a1f1dSLionel Sambuc
1022*0a6a1f1dSLionel Sambuc SET_EXTENDED_OP(low6);
1023*0a6a1f1dSLionel Sambuc
1024*0a6a1f1dSLionel Sambuc switch (low6) {
1025*0a6a1f1dSLionel Sambuc case DW_CFA_set_loc:
1026*0a6a1f1dSLionel Sambuc uoff = dbg->decode(&p, dbg->dbg_pointer_size);
1027*0a6a1f1dSLionel Sambuc SET_OFFSET(uoff);
1028*0a6a1f1dSLionel Sambuc break;
1029*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc1:
1030*0a6a1f1dSLionel Sambuc uoff = dbg->decode(&p, 1);
1031*0a6a1f1dSLionel Sambuc SET_OFFSET(uoff);
1032*0a6a1f1dSLionel Sambuc break;
1033*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc2:
1034*0a6a1f1dSLionel Sambuc uoff = dbg->decode(&p, 2);
1035*0a6a1f1dSLionel Sambuc SET_OFFSET(uoff);
1036*0a6a1f1dSLionel Sambuc break;
1037*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc4:
1038*0a6a1f1dSLionel Sambuc uoff = dbg->decode(&p, 4);
1039*0a6a1f1dSLionel Sambuc SET_OFFSET(uoff);
1040*0a6a1f1dSLionel Sambuc break;
1041*0a6a1f1dSLionel Sambuc case DW_CFA_offset_extended:
1042*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa:
1043*0a6a1f1dSLionel Sambuc case DW_CFA_val_offset:
1044*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
1045*0a6a1f1dSLionel Sambuc uoff = _dwarf_decode_uleb128(&p);
1046*0a6a1f1dSLionel Sambuc SET_REGISTER(reg);
1047*0a6a1f1dSLionel Sambuc SET_OFFSET(uoff);
1048*0a6a1f1dSLionel Sambuc break;
1049*0a6a1f1dSLionel Sambuc case DW_CFA_restore_extended:
1050*0a6a1f1dSLionel Sambuc case DW_CFA_undefined:
1051*0a6a1f1dSLionel Sambuc case DW_CFA_same_value:
1052*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_register:
1053*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
1054*0a6a1f1dSLionel Sambuc SET_REGISTER(reg);
1055*0a6a1f1dSLionel Sambuc break;
1056*0a6a1f1dSLionel Sambuc case DW_CFA_register:
1057*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
1058*0a6a1f1dSLionel Sambuc reg2 = _dwarf_decode_uleb128(&p);
1059*0a6a1f1dSLionel Sambuc SET_REGISTER(reg);
1060*0a6a1f1dSLionel Sambuc SET_OFFSET(reg2);
1061*0a6a1f1dSLionel Sambuc break;
1062*0a6a1f1dSLionel Sambuc case DW_CFA_remember_state:
1063*0a6a1f1dSLionel Sambuc case DW_CFA_restore_state:
1064*0a6a1f1dSLionel Sambuc break;
1065*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_offset:
1066*0a6a1f1dSLionel Sambuc uoff = _dwarf_decode_uleb128(&p);
1067*0a6a1f1dSLionel Sambuc SET_OFFSET(uoff);
1068*0a6a1f1dSLionel Sambuc break;
1069*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_expression:
1070*0a6a1f1dSLionel Sambuc blen = _dwarf_decode_uleb128(&p);
1071*0a6a1f1dSLionel Sambuc SET_BLOCK_LEN(blen);
1072*0a6a1f1dSLionel Sambuc SET_EXPR_BLOCK(p, blen);
1073*0a6a1f1dSLionel Sambuc p += blen;
1074*0a6a1f1dSLionel Sambuc break;
1075*0a6a1f1dSLionel Sambuc case DW_CFA_expression:
1076*0a6a1f1dSLionel Sambuc case DW_CFA_val_expression:
1077*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
1078*0a6a1f1dSLionel Sambuc blen = _dwarf_decode_uleb128(&p);
1079*0a6a1f1dSLionel Sambuc SET_REGISTER(reg);
1080*0a6a1f1dSLionel Sambuc SET_BLOCK_LEN(blen);
1081*0a6a1f1dSLionel Sambuc SET_EXPR_BLOCK(p, blen);
1082*0a6a1f1dSLionel Sambuc p += blen;
1083*0a6a1f1dSLionel Sambuc break;
1084*0a6a1f1dSLionel Sambuc case DW_CFA_offset_extended_sf:
1085*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_sf:
1086*0a6a1f1dSLionel Sambuc case DW_CFA_val_offset_sf:
1087*0a6a1f1dSLionel Sambuc reg = _dwarf_decode_uleb128(&p);
1088*0a6a1f1dSLionel Sambuc soff = _dwarf_decode_sleb128(&p);
1089*0a6a1f1dSLionel Sambuc SET_REGISTER(reg);
1090*0a6a1f1dSLionel Sambuc SET_OFFSET(soff);
1091*0a6a1f1dSLionel Sambuc break;
1092*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_offset_sf:
1093*0a6a1f1dSLionel Sambuc soff = _dwarf_decode_sleb128(&p);
1094*0a6a1f1dSLionel Sambuc SET_OFFSET(soff);
1095*0a6a1f1dSLionel Sambuc break;
1096*0a6a1f1dSLionel Sambuc default:
1097*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error,
1098*0a6a1f1dSLionel Sambuc DW_DLE_FRAME_INSTR_EXEC_ERROR);
1099*0a6a1f1dSLionel Sambuc return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1100*0a6a1f1dSLionel Sambuc }
1101*0a6a1f1dSLionel Sambuc
1102*0a6a1f1dSLionel Sambuc (*count)++;
1103*0a6a1f1dSLionel Sambuc }
1104*0a6a1f1dSLionel Sambuc
1105*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1106*0a6a1f1dSLionel Sambuc }
1107*0a6a1f1dSLionel Sambuc
1108*0a6a1f1dSLionel Sambuc int
_dwarf_frame_get_fop(Dwarf_Debug dbg,uint8_t * insts,Dwarf_Unsigned len,Dwarf_Frame_Op ** ret_oplist,Dwarf_Signed * ret_opcnt,Dwarf_Error * error)1109*0a6a1f1dSLionel Sambuc _dwarf_frame_get_fop(Dwarf_Debug dbg, uint8_t *insts, Dwarf_Unsigned len,
1110*0a6a1f1dSLionel Sambuc Dwarf_Frame_Op **ret_oplist, Dwarf_Signed *ret_opcnt, Dwarf_Error *error)
1111*0a6a1f1dSLionel Sambuc {
1112*0a6a1f1dSLionel Sambuc Dwarf_Frame_Op *oplist;
1113*0a6a1f1dSLionel Sambuc Dwarf_Unsigned count;
1114*0a6a1f1dSLionel Sambuc int ret;
1115*0a6a1f1dSLionel Sambuc
1116*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_convert_inst(dbg, insts, len, &count, NULL, NULL,
1117*0a6a1f1dSLionel Sambuc error);
1118*0a6a1f1dSLionel Sambuc if (ret != DW_DLE_NONE)
1119*0a6a1f1dSLionel Sambuc return (ret);
1120*0a6a1f1dSLionel Sambuc
1121*0a6a1f1dSLionel Sambuc if ((oplist = calloc(count, sizeof(Dwarf_Frame_Op))) == NULL) {
1122*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1123*0a6a1f1dSLionel Sambuc return (DW_DLE_MEMORY);
1124*0a6a1f1dSLionel Sambuc }
1125*0a6a1f1dSLionel Sambuc
1126*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_convert_inst(dbg, insts, len, &count, oplist, NULL,
1127*0a6a1f1dSLionel Sambuc error);
1128*0a6a1f1dSLionel Sambuc if (ret != DW_DLE_NONE) {
1129*0a6a1f1dSLionel Sambuc free(oplist);
1130*0a6a1f1dSLionel Sambuc return (ret);
1131*0a6a1f1dSLionel Sambuc }
1132*0a6a1f1dSLionel Sambuc
1133*0a6a1f1dSLionel Sambuc *ret_oplist = oplist;
1134*0a6a1f1dSLionel Sambuc *ret_opcnt = count;
1135*0a6a1f1dSLionel Sambuc
1136*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1137*0a6a1f1dSLionel Sambuc }
1138*0a6a1f1dSLionel Sambuc
1139*0a6a1f1dSLionel Sambuc int
_dwarf_frame_regtable_copy(Dwarf_Debug dbg,Dwarf_Regtable3 ** dest,Dwarf_Regtable3 * src,Dwarf_Error * error)1140*0a6a1f1dSLionel Sambuc _dwarf_frame_regtable_copy(Dwarf_Debug dbg, Dwarf_Regtable3 **dest,
1141*0a6a1f1dSLionel Sambuc Dwarf_Regtable3 *src, Dwarf_Error *error)
1142*0a6a1f1dSLionel Sambuc {
1143*0a6a1f1dSLionel Sambuc int i;
1144*0a6a1f1dSLionel Sambuc
1145*0a6a1f1dSLionel Sambuc assert(dest != NULL);
1146*0a6a1f1dSLionel Sambuc assert(src != NULL);
1147*0a6a1f1dSLionel Sambuc
1148*0a6a1f1dSLionel Sambuc if (*dest == NULL) {
1149*0a6a1f1dSLionel Sambuc if ((*dest = malloc(sizeof(Dwarf_Regtable3))) == NULL) {
1150*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1151*0a6a1f1dSLionel Sambuc return (DW_DLE_MEMORY);
1152*0a6a1f1dSLionel Sambuc }
1153*0a6a1f1dSLionel Sambuc (*dest)->rt3_reg_table_size = src->rt3_reg_table_size;
1154*0a6a1f1dSLionel Sambuc (*dest)->rt3_rules = malloc(src->rt3_reg_table_size *
1155*0a6a1f1dSLionel Sambuc sizeof(Dwarf_Regtable_Entry3));
1156*0a6a1f1dSLionel Sambuc if ((*dest)->rt3_rules == NULL) {
1157*0a6a1f1dSLionel Sambuc free(*dest);
1158*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1159*0a6a1f1dSLionel Sambuc return (DW_DLE_MEMORY);
1160*0a6a1f1dSLionel Sambuc }
1161*0a6a1f1dSLionel Sambuc }
1162*0a6a1f1dSLionel Sambuc
1163*0a6a1f1dSLionel Sambuc memcpy(&(*dest)->rt3_cfa_rule, &src->rt3_cfa_rule,
1164*0a6a1f1dSLionel Sambuc sizeof(Dwarf_Regtable_Entry3));
1165*0a6a1f1dSLionel Sambuc
1166*0a6a1f1dSLionel Sambuc for (i = 0; i < (*dest)->rt3_reg_table_size &&
1167*0a6a1f1dSLionel Sambuc i < src->rt3_reg_table_size; i++)
1168*0a6a1f1dSLionel Sambuc memcpy(&(*dest)->rt3_rules[i], &src->rt3_rules[i],
1169*0a6a1f1dSLionel Sambuc sizeof(Dwarf_Regtable_Entry3));
1170*0a6a1f1dSLionel Sambuc
1171*0a6a1f1dSLionel Sambuc for (; i < (*dest)->rt3_reg_table_size; i++)
1172*0a6a1f1dSLionel Sambuc (*dest)->rt3_rules[i].dw_regnum =
1173*0a6a1f1dSLionel Sambuc dbg->dbg_frame_undefined_value;
1174*0a6a1f1dSLionel Sambuc
1175*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1176*0a6a1f1dSLionel Sambuc }
1177*0a6a1f1dSLionel Sambuc
1178*0a6a1f1dSLionel Sambuc int
_dwarf_frame_get_internal_table(Dwarf_Fde fde,Dwarf_Addr pc_req,Dwarf_Regtable3 ** ret_rt,Dwarf_Addr * ret_row_pc,Dwarf_Error * error)1179*0a6a1f1dSLionel Sambuc _dwarf_frame_get_internal_table(Dwarf_Fde fde, Dwarf_Addr pc_req,
1180*0a6a1f1dSLionel Sambuc Dwarf_Regtable3 **ret_rt, Dwarf_Addr *ret_row_pc, Dwarf_Error *error)
1181*0a6a1f1dSLionel Sambuc {
1182*0a6a1f1dSLionel Sambuc Dwarf_Debug dbg;
1183*0a6a1f1dSLionel Sambuc Dwarf_Cie cie;
1184*0a6a1f1dSLionel Sambuc Dwarf_Regtable3 *rt;
1185*0a6a1f1dSLionel Sambuc Dwarf_Addr row_pc;
1186*0a6a1f1dSLionel Sambuc int i, ret;
1187*0a6a1f1dSLionel Sambuc
1188*0a6a1f1dSLionel Sambuc assert(ret_rt != NULL);
1189*0a6a1f1dSLionel Sambuc
1190*0a6a1f1dSLionel Sambuc dbg = fde->fde_dbg;
1191*0a6a1f1dSLionel Sambuc assert(dbg != NULL);
1192*0a6a1f1dSLionel Sambuc
1193*0a6a1f1dSLionel Sambuc rt = dbg->dbg_internal_reg_table;
1194*0a6a1f1dSLionel Sambuc
1195*0a6a1f1dSLionel Sambuc /* Clear the content of regtable from previous run. */
1196*0a6a1f1dSLionel Sambuc memset(&rt->rt3_cfa_rule, 0, sizeof(Dwarf_Regtable_Entry3));
1197*0a6a1f1dSLionel Sambuc memset(rt->rt3_rules, 0, rt->rt3_reg_table_size *
1198*0a6a1f1dSLionel Sambuc sizeof(Dwarf_Regtable_Entry3));
1199*0a6a1f1dSLionel Sambuc
1200*0a6a1f1dSLionel Sambuc /* Set rules to initial values. */
1201*0a6a1f1dSLionel Sambuc for (i = 0; i < rt->rt3_reg_table_size; i++)
1202*0a6a1f1dSLionel Sambuc rt->rt3_rules[i].dw_regnum = dbg->dbg_frame_rule_initial_value;
1203*0a6a1f1dSLionel Sambuc
1204*0a6a1f1dSLionel Sambuc /* Run initial instructions in CIE. */
1205*0a6a1f1dSLionel Sambuc cie = fde->fde_cie;
1206*0a6a1f1dSLionel Sambuc assert(cie != NULL);
1207*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_initinst,
1208*0a6a1f1dSLionel Sambuc cie->cie_instlen, cie->cie_caf, cie->cie_daf, 0, ~0ULL,
1209*0a6a1f1dSLionel Sambuc &row_pc, error);
1210*0a6a1f1dSLionel Sambuc if (ret != DW_DLE_NONE)
1211*0a6a1f1dSLionel Sambuc return (ret);
1212*0a6a1f1dSLionel Sambuc
1213*0a6a1f1dSLionel Sambuc /* Run instructions in FDE. */
1214*0a6a1f1dSLionel Sambuc if (pc_req >= fde->fde_initloc) {
1215*0a6a1f1dSLionel Sambuc ret = _dwarf_frame_run_inst(dbg, rt, fde->fde_inst,
1216*0a6a1f1dSLionel Sambuc fde->fde_instlen, cie->cie_caf, cie->cie_daf,
1217*0a6a1f1dSLionel Sambuc fde->fde_initloc, pc_req, &row_pc, error);
1218*0a6a1f1dSLionel Sambuc if (ret != DW_DLE_NONE)
1219*0a6a1f1dSLionel Sambuc return (ret);
1220*0a6a1f1dSLionel Sambuc }
1221*0a6a1f1dSLionel Sambuc
1222*0a6a1f1dSLionel Sambuc *ret_rt = rt;
1223*0a6a1f1dSLionel Sambuc *ret_row_pc = row_pc;
1224*0a6a1f1dSLionel Sambuc
1225*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1226*0a6a1f1dSLionel Sambuc }
1227*0a6a1f1dSLionel Sambuc
1228*0a6a1f1dSLionel Sambuc void
_dwarf_frame_cleanup(Dwarf_Debug dbg)1229*0a6a1f1dSLionel Sambuc _dwarf_frame_cleanup(Dwarf_Debug dbg)
1230*0a6a1f1dSLionel Sambuc {
1231*0a6a1f1dSLionel Sambuc Dwarf_Regtable3 *rt;
1232*0a6a1f1dSLionel Sambuc
1233*0a6a1f1dSLionel Sambuc assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ);
1234*0a6a1f1dSLionel Sambuc
1235*0a6a1f1dSLionel Sambuc if (dbg->dbg_internal_reg_table) {
1236*0a6a1f1dSLionel Sambuc rt = dbg->dbg_internal_reg_table;
1237*0a6a1f1dSLionel Sambuc free(rt->rt3_rules);
1238*0a6a1f1dSLionel Sambuc free(rt);
1239*0a6a1f1dSLionel Sambuc dbg->dbg_internal_reg_table = NULL;
1240*0a6a1f1dSLionel Sambuc }
1241*0a6a1f1dSLionel Sambuc
1242*0a6a1f1dSLionel Sambuc if (dbg->dbg_frame) {
1243*0a6a1f1dSLionel Sambuc _dwarf_frame_section_cleanup(dbg->dbg_frame);
1244*0a6a1f1dSLionel Sambuc dbg->dbg_frame = NULL;
1245*0a6a1f1dSLionel Sambuc }
1246*0a6a1f1dSLionel Sambuc
1247*0a6a1f1dSLionel Sambuc if (dbg->dbg_eh_frame) {
1248*0a6a1f1dSLionel Sambuc _dwarf_frame_section_cleanup(dbg->dbg_eh_frame);
1249*0a6a1f1dSLionel Sambuc dbg->dbg_eh_frame = NULL;
1250*0a6a1f1dSLionel Sambuc }
1251*0a6a1f1dSLionel Sambuc }
1252*0a6a1f1dSLionel Sambuc
1253*0a6a1f1dSLionel Sambuc int
_dwarf_frame_section_load(Dwarf_Debug dbg,Dwarf_Error * error)1254*0a6a1f1dSLionel Sambuc _dwarf_frame_section_load(Dwarf_Debug dbg, Dwarf_Error *error)
1255*0a6a1f1dSLionel Sambuc {
1256*0a6a1f1dSLionel Sambuc Dwarf_Section *ds;
1257*0a6a1f1dSLionel Sambuc
1258*0a6a1f1dSLionel Sambuc if ((ds = _dwarf_find_section(dbg, ".debug_frame")) != NULL) {
1259*0a6a1f1dSLionel Sambuc return (_dwarf_frame_section_init(dbg, &dbg->dbg_frame,
1260*0a6a1f1dSLionel Sambuc ds, 0, error));
1261*0a6a1f1dSLionel Sambuc }
1262*0a6a1f1dSLionel Sambuc
1263*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1264*0a6a1f1dSLionel Sambuc }
1265*0a6a1f1dSLionel Sambuc
1266*0a6a1f1dSLionel Sambuc int
_dwarf_frame_section_load_eh(Dwarf_Debug dbg,Dwarf_Error * error)1267*0a6a1f1dSLionel Sambuc _dwarf_frame_section_load_eh(Dwarf_Debug dbg, Dwarf_Error *error)
1268*0a6a1f1dSLionel Sambuc {
1269*0a6a1f1dSLionel Sambuc Dwarf_Section *ds;
1270*0a6a1f1dSLionel Sambuc
1271*0a6a1f1dSLionel Sambuc if ((ds = _dwarf_find_section(dbg, ".eh_frame")) != NULL) {
1272*0a6a1f1dSLionel Sambuc return (_dwarf_frame_section_init(dbg, &dbg->dbg_eh_frame,
1273*0a6a1f1dSLionel Sambuc ds, 1, error));
1274*0a6a1f1dSLionel Sambuc }
1275*0a6a1f1dSLionel Sambuc
1276*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1277*0a6a1f1dSLionel Sambuc }
1278*0a6a1f1dSLionel Sambuc
1279*0a6a1f1dSLionel Sambuc void
_dwarf_frame_params_init(Dwarf_Debug dbg)1280*0a6a1f1dSLionel Sambuc _dwarf_frame_params_init(Dwarf_Debug dbg)
1281*0a6a1f1dSLionel Sambuc {
1282*0a6a1f1dSLionel Sambuc
1283*0a6a1f1dSLionel Sambuc /* Initialise call frame related parameters. */
1284*0a6a1f1dSLionel Sambuc dbg->dbg_frame_rule_table_size = DW_FRAME_LAST_REG_NUM;
1285*0a6a1f1dSLionel Sambuc dbg->dbg_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE;
1286*0a6a1f1dSLionel Sambuc dbg->dbg_frame_cfa_value = DW_FRAME_CFA_COL3;
1287*0a6a1f1dSLionel Sambuc dbg->dbg_frame_same_value = DW_FRAME_SAME_VAL;
1288*0a6a1f1dSLionel Sambuc dbg->dbg_frame_undefined_value = DW_FRAME_UNDEFINED_VAL;
1289*0a6a1f1dSLionel Sambuc }
1290*0a6a1f1dSLionel Sambuc
1291*0a6a1f1dSLionel Sambuc int
_dwarf_frame_interal_table_init(Dwarf_Debug dbg,Dwarf_Error * error)1292*0a6a1f1dSLionel Sambuc _dwarf_frame_interal_table_init(Dwarf_Debug dbg, Dwarf_Error *error)
1293*0a6a1f1dSLionel Sambuc {
1294*0a6a1f1dSLionel Sambuc Dwarf_Regtable3 *rt;
1295*0a6a1f1dSLionel Sambuc
1296*0a6a1f1dSLionel Sambuc if (dbg->dbg_internal_reg_table != NULL)
1297*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1298*0a6a1f1dSLionel Sambuc
1299*0a6a1f1dSLionel Sambuc /* Initialise internal register table. */
1300*0a6a1f1dSLionel Sambuc if ((rt = calloc(1, sizeof(Dwarf_Regtable3))) == NULL) {
1301*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1302*0a6a1f1dSLionel Sambuc return (DW_DLE_MEMORY);
1303*0a6a1f1dSLionel Sambuc }
1304*0a6a1f1dSLionel Sambuc
1305*0a6a1f1dSLionel Sambuc rt->rt3_reg_table_size = dbg->dbg_frame_rule_table_size;
1306*0a6a1f1dSLionel Sambuc if ((rt->rt3_rules = calloc(rt->rt3_reg_table_size,
1307*0a6a1f1dSLionel Sambuc sizeof(Dwarf_Regtable_Entry3))) == NULL) {
1308*0a6a1f1dSLionel Sambuc free(rt);
1309*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1310*0a6a1f1dSLionel Sambuc return (DW_DLE_MEMORY);
1311*0a6a1f1dSLionel Sambuc }
1312*0a6a1f1dSLionel Sambuc
1313*0a6a1f1dSLionel Sambuc dbg->dbg_internal_reg_table = rt;
1314*0a6a1f1dSLionel Sambuc
1315*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1316*0a6a1f1dSLionel Sambuc }
1317*0a6a1f1dSLionel Sambuc
1318*0a6a1f1dSLionel Sambuc #define _FDE_INST_INIT_SIZE 128
1319*0a6a1f1dSLionel Sambuc
1320*0a6a1f1dSLionel Sambuc int
_dwarf_frame_fde_add_inst(Dwarf_P_Fde fde,Dwarf_Small op,Dwarf_Unsigned val1,Dwarf_Unsigned val2,Dwarf_Error * error)1321*0a6a1f1dSLionel Sambuc _dwarf_frame_fde_add_inst(Dwarf_P_Fde fde, Dwarf_Small op, Dwarf_Unsigned val1,
1322*0a6a1f1dSLionel Sambuc Dwarf_Unsigned val2, Dwarf_Error *error)
1323*0a6a1f1dSLionel Sambuc {
1324*0a6a1f1dSLionel Sambuc Dwarf_P_Debug dbg;
1325*0a6a1f1dSLionel Sambuc uint8_t high2, low6;
1326*0a6a1f1dSLionel Sambuc int ret;
1327*0a6a1f1dSLionel Sambuc
1328*0a6a1f1dSLionel Sambuc #define ds fde
1329*0a6a1f1dSLionel Sambuc #define ds_data fde_inst
1330*0a6a1f1dSLionel Sambuc #define ds_cap fde_instcap
1331*0a6a1f1dSLionel Sambuc #define ds_size fde_instlen
1332*0a6a1f1dSLionel Sambuc
1333*0a6a1f1dSLionel Sambuc assert(fde != NULL && fde->fde_dbg != NULL);
1334*0a6a1f1dSLionel Sambuc dbg = fde->fde_dbg;
1335*0a6a1f1dSLionel Sambuc
1336*0a6a1f1dSLionel Sambuc if (fde->fde_inst == NULL) {
1337*0a6a1f1dSLionel Sambuc fde->fde_instcap = _FDE_INST_INIT_SIZE;
1338*0a6a1f1dSLionel Sambuc fde->fde_instlen = 0;
1339*0a6a1f1dSLionel Sambuc if ((fde->fde_inst = malloc((size_t) fde->fde_instcap)) ==
1340*0a6a1f1dSLionel Sambuc NULL) {
1341*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1342*0a6a1f1dSLionel Sambuc return (DW_DLE_MEMORY);
1343*0a6a1f1dSLionel Sambuc }
1344*0a6a1f1dSLionel Sambuc }
1345*0a6a1f1dSLionel Sambuc assert(fde->fde_instcap != 0);
1346*0a6a1f1dSLionel Sambuc
1347*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(op, 1));
1348*0a6a1f1dSLionel Sambuc if (op == DW_CFA_nop)
1349*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1350*0a6a1f1dSLionel Sambuc
1351*0a6a1f1dSLionel Sambuc high2 = op & 0xc0;
1352*0a6a1f1dSLionel Sambuc low6 = op & 0x3f;
1353*0a6a1f1dSLionel Sambuc
1354*0a6a1f1dSLionel Sambuc if (high2 > 0) {
1355*0a6a1f1dSLionel Sambuc switch (high2) {
1356*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc:
1357*0a6a1f1dSLionel Sambuc case DW_CFA_restore:
1358*0a6a1f1dSLionel Sambuc break;
1359*0a6a1f1dSLionel Sambuc case DW_CFA_offset:
1360*0a6a1f1dSLionel Sambuc RCHECK(WRITE_ULEB128(val1));
1361*0a6a1f1dSLionel Sambuc break;
1362*0a6a1f1dSLionel Sambuc default:
1363*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error,
1364*0a6a1f1dSLionel Sambuc DW_DLE_FRAME_INSTR_EXEC_ERROR);
1365*0a6a1f1dSLionel Sambuc return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1366*0a6a1f1dSLionel Sambuc }
1367*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1368*0a6a1f1dSLionel Sambuc }
1369*0a6a1f1dSLionel Sambuc
1370*0a6a1f1dSLionel Sambuc switch (low6) {
1371*0a6a1f1dSLionel Sambuc case DW_CFA_set_loc:
1372*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(val1, dbg->dbg_pointer_size));
1373*0a6a1f1dSLionel Sambuc break;
1374*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc1:
1375*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(val1, 1));
1376*0a6a1f1dSLionel Sambuc break;
1377*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc2:
1378*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(val1, 2));
1379*0a6a1f1dSLionel Sambuc break;
1380*0a6a1f1dSLionel Sambuc case DW_CFA_advance_loc4:
1381*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(val1, 4));
1382*0a6a1f1dSLionel Sambuc break;
1383*0a6a1f1dSLionel Sambuc case DW_CFA_offset_extended:
1384*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa:
1385*0a6a1f1dSLionel Sambuc case DW_CFA_register:
1386*0a6a1f1dSLionel Sambuc RCHECK(WRITE_ULEB128(val1));
1387*0a6a1f1dSLionel Sambuc RCHECK(WRITE_ULEB128(val2));
1388*0a6a1f1dSLionel Sambuc break;
1389*0a6a1f1dSLionel Sambuc case DW_CFA_restore_extended:
1390*0a6a1f1dSLionel Sambuc case DW_CFA_undefined:
1391*0a6a1f1dSLionel Sambuc case DW_CFA_same_value:
1392*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_register:
1393*0a6a1f1dSLionel Sambuc case DW_CFA_def_cfa_offset:
1394*0a6a1f1dSLionel Sambuc RCHECK(WRITE_ULEB128(val1));
1395*0a6a1f1dSLionel Sambuc break;
1396*0a6a1f1dSLionel Sambuc case DW_CFA_remember_state:
1397*0a6a1f1dSLionel Sambuc case DW_CFA_restore_state:
1398*0a6a1f1dSLionel Sambuc break;
1399*0a6a1f1dSLionel Sambuc default:
1400*0a6a1f1dSLionel Sambuc DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR);
1401*0a6a1f1dSLionel Sambuc return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1402*0a6a1f1dSLionel Sambuc }
1403*0a6a1f1dSLionel Sambuc
1404*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1405*0a6a1f1dSLionel Sambuc
1406*0a6a1f1dSLionel Sambuc gen_fail:
1407*0a6a1f1dSLionel Sambuc return (ret);
1408*0a6a1f1dSLionel Sambuc
1409*0a6a1f1dSLionel Sambuc #undef ds
1410*0a6a1f1dSLionel Sambuc #undef ds_data
1411*0a6a1f1dSLionel Sambuc #undef ds_cap
1412*0a6a1f1dSLionel Sambuc #undef ds_size
1413*0a6a1f1dSLionel Sambuc }
1414*0a6a1f1dSLionel Sambuc
1415*0a6a1f1dSLionel Sambuc static int
_dwarf_frame_gen_cie(Dwarf_P_Debug dbg,Dwarf_P_Section ds,Dwarf_P_Cie cie,Dwarf_Error * error)1416*0a6a1f1dSLionel Sambuc _dwarf_frame_gen_cie(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_P_Cie cie,
1417*0a6a1f1dSLionel Sambuc Dwarf_Error *error)
1418*0a6a1f1dSLionel Sambuc {
1419*0a6a1f1dSLionel Sambuc Dwarf_Unsigned len;
1420*0a6a1f1dSLionel Sambuc uint64_t offset;
1421*0a6a1f1dSLionel Sambuc int ret;
1422*0a6a1f1dSLionel Sambuc
1423*0a6a1f1dSLionel Sambuc assert(dbg != NULL && ds != NULL && cie != NULL);
1424*0a6a1f1dSLionel Sambuc
1425*0a6a1f1dSLionel Sambuc cie->cie_offset = offset = ds->ds_size;
1426*0a6a1f1dSLionel Sambuc cie->cie_length = 0;
1427*0a6a1f1dSLionel Sambuc cie->cie_version = 1;
1428*0a6a1f1dSLionel Sambuc
1429*0a6a1f1dSLionel Sambuc /* Length placeholder. */
1430*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(cie->cie_length, 4));
1431*0a6a1f1dSLionel Sambuc
1432*0a6a1f1dSLionel Sambuc /* .debug_frame use CIE id ~0. */
1433*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(~0U, 4));
1434*0a6a1f1dSLionel Sambuc
1435*0a6a1f1dSLionel Sambuc /* .debug_frame version is 1. (DWARF2) */
1436*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(cie->cie_version, 1));
1437*0a6a1f1dSLionel Sambuc
1438*0a6a1f1dSLionel Sambuc /* Write augmentation, if present. */
1439*0a6a1f1dSLionel Sambuc if (cie->cie_augment != NULL)
1440*0a6a1f1dSLionel Sambuc RCHECK(WRITE_BLOCK(cie->cie_augment,
1441*0a6a1f1dSLionel Sambuc strlen((char *) cie->cie_augment) + 1));
1442*0a6a1f1dSLionel Sambuc else
1443*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(0, 1));
1444*0a6a1f1dSLionel Sambuc
1445*0a6a1f1dSLionel Sambuc /* Write caf, daf and ra. */
1446*0a6a1f1dSLionel Sambuc RCHECK(WRITE_ULEB128(cie->cie_caf));
1447*0a6a1f1dSLionel Sambuc RCHECK(WRITE_SLEB128(cie->cie_daf));
1448*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(cie->cie_ra, 1));
1449*0a6a1f1dSLionel Sambuc
1450*0a6a1f1dSLionel Sambuc /* Write initial instructions, if present. */
1451*0a6a1f1dSLionel Sambuc if (cie->cie_initinst != NULL)
1452*0a6a1f1dSLionel Sambuc RCHECK(WRITE_BLOCK(cie->cie_initinst, cie->cie_instlen));
1453*0a6a1f1dSLionel Sambuc
1454*0a6a1f1dSLionel Sambuc /* Add padding. */
1455*0a6a1f1dSLionel Sambuc len = ds->ds_size - cie->cie_offset - 4;
1456*0a6a1f1dSLionel Sambuc cie->cie_length = roundup(len, dbg->dbg_pointer_size);
1457*0a6a1f1dSLionel Sambuc while (len++ < cie->cie_length)
1458*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(DW_CFA_nop, 1));
1459*0a6a1f1dSLionel Sambuc
1460*0a6a1f1dSLionel Sambuc /* Fill in the length field. */
1461*0a6a1f1dSLionel Sambuc dbg->write(ds->ds_data, &offset, cie->cie_length, 4);
1462*0a6a1f1dSLionel Sambuc
1463*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1464*0a6a1f1dSLionel Sambuc
1465*0a6a1f1dSLionel Sambuc gen_fail:
1466*0a6a1f1dSLionel Sambuc return (ret);
1467*0a6a1f1dSLionel Sambuc }
1468*0a6a1f1dSLionel Sambuc
1469*0a6a1f1dSLionel Sambuc static int
_dwarf_frame_gen_fde(Dwarf_P_Debug dbg,Dwarf_P_Section ds,Dwarf_Rel_Section drs,Dwarf_P_Fde fde,Dwarf_Error * error)1470*0a6a1f1dSLionel Sambuc _dwarf_frame_gen_fde(Dwarf_P_Debug dbg, Dwarf_P_Section ds,
1471*0a6a1f1dSLionel Sambuc Dwarf_Rel_Section drs, Dwarf_P_Fde fde, Dwarf_Error *error)
1472*0a6a1f1dSLionel Sambuc {
1473*0a6a1f1dSLionel Sambuc Dwarf_Unsigned len;
1474*0a6a1f1dSLionel Sambuc uint64_t offset;
1475*0a6a1f1dSLionel Sambuc int ret;
1476*0a6a1f1dSLionel Sambuc
1477*0a6a1f1dSLionel Sambuc assert(dbg != NULL && ds != NULL && drs != NULL);
1478*0a6a1f1dSLionel Sambuc assert(fde != NULL && fde->fde_cie != NULL);
1479*0a6a1f1dSLionel Sambuc
1480*0a6a1f1dSLionel Sambuc fde->fde_offset = offset = ds->ds_size;
1481*0a6a1f1dSLionel Sambuc fde->fde_length = 0;
1482*0a6a1f1dSLionel Sambuc fde->fde_cieoff = fde->fde_cie->cie_offset;
1483*0a6a1f1dSLionel Sambuc
1484*0a6a1f1dSLionel Sambuc /* Length placeholder. */
1485*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(fde->fde_length, 4));
1486*0a6a1f1dSLionel Sambuc
1487*0a6a1f1dSLionel Sambuc /* Write CIE pointer. */
1488*0a6a1f1dSLionel Sambuc RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4,
1489*0a6a1f1dSLionel Sambuc ds->ds_size, 0, fde->fde_cieoff, ".debug_frame", error));
1490*0a6a1f1dSLionel Sambuc
1491*0a6a1f1dSLionel Sambuc /* Write FDE initial location. */
1492*0a6a1f1dSLionel Sambuc RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc,
1493*0a6a1f1dSLionel Sambuc dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx,
1494*0a6a1f1dSLionel Sambuc fde->fde_initloc, NULL, error));
1495*0a6a1f1dSLionel Sambuc
1496*0a6a1f1dSLionel Sambuc /*
1497*0a6a1f1dSLionel Sambuc * Write FDE address range. Use a pair of relocation entries if
1498*0a6a1f1dSLionel Sambuc * application provided end symbol index. Otherwise write the
1499*0a6a1f1dSLionel Sambuc * length without assoicating any relocation info.
1500*0a6a1f1dSLionel Sambuc */
1501*0a6a1f1dSLionel Sambuc if (fde->fde_esymndx > 0)
1502*0a6a1f1dSLionel Sambuc RCHECK(_dwarf_reloc_entry_add_pair(dbg, drs, ds,
1503*0a6a1f1dSLionel Sambuc dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx,
1504*0a6a1f1dSLionel Sambuc fde->fde_esymndx, fde->fde_initloc, fde->fde_eoff, error));
1505*0a6a1f1dSLionel Sambuc else
1506*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(fde->fde_adrange, dbg->dbg_pointer_size));
1507*0a6a1f1dSLionel Sambuc
1508*0a6a1f1dSLionel Sambuc /* Write FDE frame instructions. */
1509*0a6a1f1dSLionel Sambuc RCHECK(WRITE_BLOCK(fde->fde_inst, fde->fde_instlen));
1510*0a6a1f1dSLionel Sambuc
1511*0a6a1f1dSLionel Sambuc /* Add padding. */
1512*0a6a1f1dSLionel Sambuc len = ds->ds_size - fde->fde_offset - 4;
1513*0a6a1f1dSLionel Sambuc fde->fde_length = roundup(len, dbg->dbg_pointer_size);
1514*0a6a1f1dSLionel Sambuc while (len++ < fde->fde_length)
1515*0a6a1f1dSLionel Sambuc RCHECK(WRITE_VALUE(DW_CFA_nop, 1));
1516*0a6a1f1dSLionel Sambuc
1517*0a6a1f1dSLionel Sambuc /* Fill in the length field. */
1518*0a6a1f1dSLionel Sambuc dbg->write(ds->ds_data, &offset, fde->fde_length, 4);
1519*0a6a1f1dSLionel Sambuc
1520*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1521*0a6a1f1dSLionel Sambuc
1522*0a6a1f1dSLionel Sambuc gen_fail:
1523*0a6a1f1dSLionel Sambuc return (ret);
1524*0a6a1f1dSLionel Sambuc }
1525*0a6a1f1dSLionel Sambuc
1526*0a6a1f1dSLionel Sambuc int
_dwarf_frame_gen(Dwarf_P_Debug dbg,Dwarf_Error * error)1527*0a6a1f1dSLionel Sambuc _dwarf_frame_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
1528*0a6a1f1dSLionel Sambuc {
1529*0a6a1f1dSLionel Sambuc Dwarf_P_Section ds;
1530*0a6a1f1dSLionel Sambuc Dwarf_Rel_Section drs;
1531*0a6a1f1dSLionel Sambuc Dwarf_P_Cie cie;
1532*0a6a1f1dSLionel Sambuc Dwarf_P_Fde fde;
1533*0a6a1f1dSLionel Sambuc int ret;
1534*0a6a1f1dSLionel Sambuc
1535*0a6a1f1dSLionel Sambuc if (STAILQ_EMPTY(&dbg->dbgp_cielist))
1536*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1537*0a6a1f1dSLionel Sambuc
1538*0a6a1f1dSLionel Sambuc /* Create .debug_frame section. */
1539*0a6a1f1dSLionel Sambuc if ((ret = _dwarf_section_init(dbg, &ds, ".debug_frame", 0, error)) !=
1540*0a6a1f1dSLionel Sambuc DW_DLE_NONE)
1541*0a6a1f1dSLionel Sambuc goto gen_fail0;
1542*0a6a1f1dSLionel Sambuc
1543*0a6a1f1dSLionel Sambuc /* Create relocation section for .debug_frame */
1544*0a6a1f1dSLionel Sambuc RCHECK(_dwarf_reloc_section_init(dbg, &drs, ds, error));
1545*0a6a1f1dSLionel Sambuc
1546*0a6a1f1dSLionel Sambuc /* Generate list of CIE. */
1547*0a6a1f1dSLionel Sambuc STAILQ_FOREACH(cie, &dbg->dbgp_cielist, cie_next)
1548*0a6a1f1dSLionel Sambuc RCHECK(_dwarf_frame_gen_cie(dbg, ds, cie, error));
1549*0a6a1f1dSLionel Sambuc
1550*0a6a1f1dSLionel Sambuc /* Generate list of FDE. */
1551*0a6a1f1dSLionel Sambuc STAILQ_FOREACH(fde, &dbg->dbgp_fdelist, fde_next)
1552*0a6a1f1dSLionel Sambuc RCHECK(_dwarf_frame_gen_fde(dbg, ds, drs, fde, error));
1553*0a6a1f1dSLionel Sambuc
1554*0a6a1f1dSLionel Sambuc /* Inform application the creation of .debug_frame ELF section. */
1555*0a6a1f1dSLionel Sambuc RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
1556*0a6a1f1dSLionel Sambuc
1557*0a6a1f1dSLionel Sambuc /* Finalize relocation section for .debug_frame */
1558*0a6a1f1dSLionel Sambuc RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error));
1559*0a6a1f1dSLionel Sambuc
1560*0a6a1f1dSLionel Sambuc return (DW_DLE_NONE);
1561*0a6a1f1dSLionel Sambuc
1562*0a6a1f1dSLionel Sambuc gen_fail:
1563*0a6a1f1dSLionel Sambuc _dwarf_reloc_section_free(dbg, &drs);
1564*0a6a1f1dSLionel Sambuc
1565*0a6a1f1dSLionel Sambuc gen_fail0:
1566*0a6a1f1dSLionel Sambuc _dwarf_section_free(dbg, &ds);
1567*0a6a1f1dSLionel Sambuc
1568*0a6a1f1dSLionel Sambuc return (ret);
1569*0a6a1f1dSLionel Sambuc }
1570*0a6a1f1dSLionel Sambuc
1571*0a6a1f1dSLionel Sambuc void
_dwarf_frame_pro_cleanup(Dwarf_P_Debug dbg)1572*0a6a1f1dSLionel Sambuc _dwarf_frame_pro_cleanup(Dwarf_P_Debug dbg)
1573*0a6a1f1dSLionel Sambuc {
1574*0a6a1f1dSLionel Sambuc Dwarf_P_Cie cie, tcie;
1575*0a6a1f1dSLionel Sambuc Dwarf_P_Fde fde, tfde;
1576*0a6a1f1dSLionel Sambuc
1577*0a6a1f1dSLionel Sambuc assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
1578*0a6a1f1dSLionel Sambuc
1579*0a6a1f1dSLionel Sambuc STAILQ_FOREACH_SAFE(cie, &dbg->dbgp_cielist, cie_next, tcie) {
1580*0a6a1f1dSLionel Sambuc STAILQ_REMOVE(&dbg->dbgp_cielist, cie, _Dwarf_Cie, cie_next);
1581*0a6a1f1dSLionel Sambuc if (cie->cie_augment)
1582*0a6a1f1dSLionel Sambuc free(cie->cie_augment);
1583*0a6a1f1dSLionel Sambuc if (cie->cie_initinst)
1584*0a6a1f1dSLionel Sambuc free(cie->cie_initinst);
1585*0a6a1f1dSLionel Sambuc free(cie);
1586*0a6a1f1dSLionel Sambuc }
1587*0a6a1f1dSLionel Sambuc dbg->dbgp_cielen = 0;
1588*0a6a1f1dSLionel Sambuc
1589*0a6a1f1dSLionel Sambuc STAILQ_FOREACH_SAFE(fde, &dbg->dbgp_fdelist, fde_next, tfde) {
1590*0a6a1f1dSLionel Sambuc STAILQ_REMOVE(&dbg->dbgp_fdelist, fde, _Dwarf_Fde, fde_next);
1591*0a6a1f1dSLionel Sambuc if (fde->fde_inst != NULL)
1592*0a6a1f1dSLionel Sambuc free(fde->fde_inst);
1593*0a6a1f1dSLionel Sambuc free(fde);
1594*0a6a1f1dSLionel Sambuc }
1595*0a6a1f1dSLionel Sambuc dbg->dbgp_fdelen = 0;
1596*0a6a1f1dSLionel Sambuc }
1597