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