1/*
2
3  Copyright (C) 2000,2004 Silicon Graphics, Inc.  All Rights Reserved.
4
5  This program is free software; you can redistribute it and/or modify it
6  under the terms of version 2.1 of the GNU Lesser General Public License
7  as published by the Free Software Foundation.
8
9  This program is distributed in the hope that it would be useful, but
10  WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13  Further, this software is distributed without any warranty that it is
14  free of the rightful claim of any third person regarding infringement
15  or the like.  Any license provided herein, whether implied or
16  otherwise, applies only to this software file.  Patent licenses, if
17  any, provided herein do not apply to combinations of this program with
18  other software, or any other product whatsoever.
19
20  You should have received a copy of the GNU Lesser General Public
21  License along with this program; if not, write the Free Software
22  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
23  USA.
24
25  Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
26  Mountain View, CA 94043, or:
27
28  http://www.sgi.com
29
30  For further information regarding this notice, see:
31
32  http://oss.sgi.com/projects/GenInfo/NoticeExplan
33
34*/
35
36
37
38#include "config.h"
39#include "libdwarfdefs.h"
40#include <stdio.h>
41#include <string.h>
42#include <limits.h>
43#include "pro_incl.h"
44#include "pro_frame.h"
45
46static void _dwarf_pro_add_to_fde(Dwarf_P_Fde fde,
47                                  Dwarf_P_Frame_Pgm inst);
48
49/*-------------------------------------------------------------------------
50        This function adds a cie struct to the debug pointer. Its in the
51        form of a linked list.
52        augmenter: string reps augmentation (implementation defined)
53        code_align: alignment of code
54        data_align: alignment of data
55        init_bytes: byts having initial instructions
56        init_n_bytes: number of bytes of initial instructions
57--------------------------------------------------------------------------*/
58Dwarf_Unsigned
59dwarf_add_frame_cie(Dwarf_P_Debug dbg,
60                    char *augmenter,
61                    Dwarf_Small code_align,
62                    Dwarf_Small data_align,
63                    Dwarf_Small return_reg,
64                    Dwarf_Ptr init_bytes,
65                    Dwarf_Unsigned init_n_bytes, Dwarf_Error * error)
66{
67    Dwarf_P_Cie curcie;
68
69    if (dbg->de_frame_cies == NULL) {
70        dbg->de_frame_cies = (Dwarf_P_Cie)
71            _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Cie_s));
72        if (dbg->de_frame_cies == NULL) {
73            DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_ALLOC, DW_DLV_NOCOUNT);
74        }
75        curcie = dbg->de_frame_cies;
76        dbg->de_n_cie = 1;
77        dbg->de_last_cie = curcie;
78    } else {
79        curcie = dbg->de_last_cie;
80        curcie->cie_next = (Dwarf_P_Cie)
81            _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Cie_s));
82        if (curcie->cie_next == NULL) {
83            DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_ALLOC, DW_DLV_NOCOUNT);
84        }
85        curcie = curcie->cie_next;
86        dbg->de_n_cie++;
87        dbg->de_last_cie = curcie;
88    }
89    curcie->cie_version = DW_CIE_VERSION;
90    curcie->cie_aug = augmenter;
91    curcie->cie_code_align = code_align;
92    curcie->cie_data_align = data_align;
93    curcie->cie_ret_reg = return_reg;
94    curcie->cie_inst = (char *) init_bytes;
95    curcie->cie_inst_bytes = (long) init_n_bytes;
96    curcie->cie_next = NULL;
97    return dbg->de_n_cie;
98}
99
100
101/*-------------------------------------------------------------------------
102        This functions adds a fde struct to the debug pointer. Its in the
103        form of a linked list.
104        die: subprogram/function die corresponding to this fde
105        cie: cie referred to by this fde, obtained from call to
106            add_frame_cie() routine.
107        virt_addr: beginning address
108        code_len: length of code reps by the fde
109--------------------------------------------------------------------------*/
110 /*ARGSUSED*/                   /* pretend all args used */
111    Dwarf_Unsigned
112dwarf_add_frame_fde(Dwarf_P_Debug dbg,
113                    Dwarf_P_Fde fde,
114                    Dwarf_P_Die die,
115                    Dwarf_Unsigned cie,
116                    Dwarf_Unsigned virt_addr,
117                    Dwarf_Unsigned code_len,
118                    Dwarf_Unsigned symidx, Dwarf_Error * error)
119{
120    return dwarf_add_frame_fde_b(dbg, fde, die, cie, virt_addr,
121                                 code_len, symidx, 0, 0, error);
122}
123
124/*ARGSUSED10*/
125Dwarf_Unsigned
126dwarf_add_frame_fde_b(Dwarf_P_Debug dbg,
127                      Dwarf_P_Fde fde,
128                      Dwarf_P_Die die,
129                      Dwarf_Unsigned cie,
130                      Dwarf_Unsigned virt_addr,
131                      Dwarf_Unsigned code_len,
132                      Dwarf_Unsigned symidx,
133                      Dwarf_Unsigned symidx_of_end,
134                      Dwarf_Addr offset_from_end_sym,
135                      Dwarf_Error * error)
136{
137    Dwarf_P_Fde curfde;
138
139    fde->fde_die = die;
140    fde->fde_cie = (long) cie;
141    fde->fde_initloc = virt_addr;
142    fde->fde_r_symidx = symidx;
143    fde->fde_addr_range = code_len;
144    fde->fde_offset_into_exception_tables = DW_DLX_NO_EH_OFFSET;
145    fde->fde_exception_table_symbol = 0;
146    fde->fde_end_symbol_offset = offset_from_end_sym;
147    fde->fde_end_symbol = symidx_of_end;
148    fde->fde_dbg = dbg;
149
150    curfde = dbg->de_last_fde;
151    if (curfde == NULL) {
152        dbg->de_frame_fdes = fde;
153        dbg->de_last_fde = fde;
154        dbg->de_n_fde = 1;
155    } else {
156        curfde->fde_next = fde;
157        dbg->de_last_fde = fde;
158        dbg->de_n_fde++;
159    }
160    return dbg->de_n_fde;
161}
162
163/*-------------------------------------------------------------------------
164        This functions adds information to an fde. The fde is
165        linked into the linked list of fde's maintained in the Dwarf_P_Debug
166        structure.
167        dbg: The debug descriptor.
168        fde: The fde to be added.
169        die: subprogram/function die corresponding to this fde
170        cie: cie referred to by this fde, obtained from call to
171            add_frame_cie() routine.
172        virt_addr: beginning address
173        code_len: length of code reps by the fde
174        symidx: The symbol id of the symbol wrt to which relocation needs
175                to be performed for 'virt_addr'.
176        offset_into_exception_tables: The start of exception tables for
177                this function (indicated as an offset into the exception
178                tables). A value of -1 indicates that there is no exception
179                table entries associated with this function.
180        exception_table_symbol: The symbol id of the section for exception
181                tables wrt to which the offset_into_exception_tables will
182                be relocated.
183--------------------------------------------------------------------------*/
184Dwarf_Unsigned
185dwarf_add_frame_info(Dwarf_P_Debug dbg,
186                     Dwarf_P_Fde fde,
187                     Dwarf_P_Die die,
188                     Dwarf_Unsigned cie,
189                     Dwarf_Unsigned virt_addr,
190                     Dwarf_Unsigned code_len,
191                     Dwarf_Unsigned symidx,
192                     Dwarf_Signed offset_into_exception_tables,
193                     Dwarf_Unsigned exception_table_symbol,
194                     Dwarf_Error * error)
195{
196
197    return dwarf_add_frame_info_b(dbg, fde, die, cie, virt_addr,
198                                  code_len, symidx,
199                                  /* end_symbol */ 0,
200                                  /* offset_from_end */ 0,
201                                  offset_into_exception_tables,
202                                  exception_table_symbol, error);
203
204}
205
206 /*ARGSUSED*/                   /* pretend all args used */
207Dwarf_Unsigned
208dwarf_add_frame_info_b(Dwarf_P_Debug dbg,
209                       Dwarf_P_Fde fde,
210                       Dwarf_P_Die die,
211                       Dwarf_Unsigned cie,
212                       Dwarf_Unsigned virt_addr,
213                       Dwarf_Unsigned code_len,
214                       Dwarf_Unsigned symidx,
215                       Dwarf_Unsigned end_symidx,
216                       Dwarf_Unsigned offset_from_end_symbol,
217                       Dwarf_Signed offset_into_exception_tables,
218                       Dwarf_Unsigned exception_table_symbol,
219                       Dwarf_Error * error)
220{
221    Dwarf_P_Fde curfde;
222
223    fde->fde_die = die;
224    fde->fde_cie = (long) cie;
225    fde->fde_initloc = virt_addr;
226    fde->fde_r_symidx = symidx;
227    fde->fde_addr_range = code_len;
228    fde->fde_offset_into_exception_tables =
229        offset_into_exception_tables;
230    fde->fde_exception_table_symbol = exception_table_symbol;
231    fde->fde_end_symbol_offset = offset_from_end_symbol;
232    fde->fde_end_symbol = end_symidx;
233    fde->fde_dbg = dbg;
234
235    curfde = dbg->de_last_fde;
236    if (curfde == NULL) {
237        dbg->de_frame_fdes = fde;
238        dbg->de_last_fde = fde;
239        dbg->de_n_fde = 1;
240    } else {
241        curfde->fde_next = fde;
242        dbg->de_last_fde = fde;
243        dbg->de_n_fde++;
244    }
245    return dbg->de_n_fde;
246}
247
248/* This is an alternate to inserting frame instructions
249   one instruction at a time.  But use either this
250   or instruction level, not both in one fde. */
251int
252dwarf_insert_fde_inst_bytes(Dwarf_P_Debug dbg,
253    Dwarf_P_Fde fde,Dwarf_Unsigned len, Dwarf_Ptr ibytes,
254    Dwarf_Error *error)
255{
256    if( len == 0) {
257        return DW_DLV_OK;
258    }
259    if(fde->fde_block || fde->fde_inst) {
260        DWARF_P_DBG_ERROR(dbg, DW_DLE_DUPLICATE_INST_BLOCK,
261            (int)DW_DLV_BADADDR);
262    }
263    fde->fde_block = (Dwarf_Ptr)_dwarf_p_get_alloc(dbg, len);
264    memcpy(fde->fde_block,ibytes,len);
265    fde->fde_inst_block_size = len;
266    fde->fde_n_bytes += len;
267    return DW_DLV_OK;
268}
269
270
271
272/*-------------------------------------------------------------------
273        Create a new fde.
274---------------------------------------------------------------------*/
275Dwarf_P_Fde
276dwarf_new_fde(Dwarf_P_Debug dbg, Dwarf_Error * error)
277{
278    Dwarf_P_Fde fde;
279
280    fde = (Dwarf_P_Fde)
281        _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Fde_s));
282    if (fde == NULL) {
283        DWARF_P_DBG_ERROR(dbg, DW_DLE_FDE_ALLOC,
284                          (Dwarf_P_Fde) DW_DLV_BADADDR);
285    }
286
287    fde->fde_uwordb_size = dbg->de_offset_size;
288
289    return fde;
290}
291
292
293/*------------------------------------------------------------------------
294        Add a cfe_offset instruction to the fde passed in.
295-------------------------------------------------------------------------*/
296Dwarf_P_Fde
297dwarf_fde_cfa_offset(Dwarf_P_Fde fde,
298                     Dwarf_Unsigned reg,
299                     Dwarf_Signed offset, Dwarf_Error * error)
300{
301    Dwarf_Ubyte opc, regno;
302    char *ptr;
303    Dwarf_P_Frame_Pgm curinst;
304    int nbytes;
305    int res;
306    char buff1[ENCODE_SPACE_NEEDED];
307    Dwarf_P_Debug dbg = fde->fde_dbg;
308
309    curinst = (Dwarf_P_Frame_Pgm)
310        _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Frame_Pgm_s));
311    if (curinst == NULL) {
312        DWARF_P_DBG_ERROR(dbg, DW_DLE_FPGM_ALLOC,
313                          (Dwarf_P_Fde) DW_DLV_BADADDR);
314    }
315    opc = DW_CFA_offset;
316    regno = reg;
317    if (regno & 0xc0) {
318        DWARF_P_DBG_ERROR(dbg, DW_DLE_REGNO_OVFL,
319                          (Dwarf_P_Fde) DW_DLV_BADADDR);
320    }
321    opc = opc | regno;          /* lower 6 bits are register number */
322    curinst->dfp_opcode = opc;
323    res = _dwarf_pro_encode_leb128_nm(offset, &nbytes,
324                                      buff1, sizeof(buff1));
325    if (res != DW_DLV_OK) {
326        _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
327        return ((Dwarf_P_Fde) DW_DLV_BADADDR);
328    }
329    ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes);
330    if (ptr == NULL) {
331        _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
332        return ((Dwarf_P_Fde) DW_DLV_BADADDR);
333    }
334    memcpy(ptr, buff1, nbytes);
335
336    curinst->dfp_args = ptr;
337    curinst->dfp_nbytes = nbytes;
338    curinst->dfp_next = NULL;
339
340    _dwarf_pro_add_to_fde(fde, curinst);
341    return fde;
342}
343
344/*
345    Generic routine to add opcode to fde instructions. val1 and
346    val2 are parameters whose interpretation depends on the 'op'.
347
348    This does not work properly for  DW_DLC_SYMBOLIC_RELOCATIONS
349    for DW_CFA_set_loc or DW_DVA_advance_loc* 'op', as
350    these ops normally are addresses or (DW_CFA_set_loc)
351    or code lengths (DW_DVA_advance_loc*) and such must be
352    represented with relocations and symbol indices for
353    DW_DLC_SYMBOLIC_RELOCATIONS.
354
355    This does not treat all DW_CFA instructions yet.
356
357    For certain operations a val? value must be
358    signed (though passed in as unsigned here).
359
360    Currently this does not check that the frame
361    version is 3(for dwarf3) or 4 (for dwarf4)
362    when applying operations that are only valid for
363    dwarf3 or dwarf4.
364
365*/
366Dwarf_P_Fde
367dwarf_add_fde_inst(Dwarf_P_Fde fde,
368                   Dwarf_Small op,
369                   Dwarf_Unsigned val1,
370                   Dwarf_Unsigned val2, Dwarf_Error * error)
371{
372    Dwarf_P_Frame_Pgm curinst;
373    int nbytes, nbytes1, nbytes2;
374    Dwarf_Ubyte db;
375    Dwarf_Half dh;
376    Dwarf_Word dw;
377    Dwarf_Unsigned du;
378    char *ptr;
379    int res;
380    char buff1[ENCODE_SPACE_NEEDED];
381    char buff2[ENCODE_SPACE_NEEDED];
382    Dwarf_P_Debug dbg = fde->fde_dbg;
383    /* This is a hack telling the code when to transform
384       a value to a signed leb number. */
385    int signed_second = 0;
386    int signed_first = 0;
387
388
389    nbytes = 0;
390    ptr = NULL;
391    curinst = (Dwarf_P_Frame_Pgm)
392        _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Frame_Pgm_s));
393    if (curinst == NULL) {
394        _dwarf_p_error(dbg, error, DW_DLE_FPGM_ALLOC);
395        return ((Dwarf_P_Fde) DW_DLV_BADADDR);
396    }
397
398    switch (op) {
399
400    case DW_CFA_advance_loc:
401        if (val1 <= 0x3f) {
402            db = val1;
403            op |= db;
404        }
405        /* test not portable FIX */
406        else if (val1 <= UCHAR_MAX) {
407            op = DW_CFA_advance_loc1;
408            db = val1;
409            ptr = (char *) _dwarf_p_get_alloc(dbg, 1);
410            if (ptr == NULL) {
411                _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
412                return ((Dwarf_P_Fde) DW_DLV_BADADDR);
413            }
414            memcpy((void *) ptr, (const void *) &db, 1);
415            nbytes = 1;
416        }
417        /* test not portable FIX */
418        else if (val1 <= USHRT_MAX) {
419            op = DW_CFA_advance_loc2;
420            dh = val1;
421            ptr = (char *) _dwarf_p_get_alloc(dbg, 2);
422            if (ptr == NULL) {
423                _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
424                return ((Dwarf_P_Fde) DW_DLV_BADADDR);
425            }
426            memcpy((void *) ptr, (const void *) &dh, 2);
427            nbytes = 2;
428        }
429        /* test not portable FIX */
430        else if (val1 <= ULONG_MAX) {
431            op = DW_CFA_advance_loc4;
432            dw = (Dwarf_Word) val1;
433            ptr = (char *) _dwarf_p_get_alloc(dbg, 4);
434            if (ptr == NULL) {
435                _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
436                return ((Dwarf_P_Fde) DW_DLV_BADADDR);
437            }
438            memcpy((void *) ptr, (const void *) &dw, 4);
439            nbytes = 4;
440        } else {
441            op = DW_CFA_MIPS_advance_loc8;
442            du = val1;
443            ptr =
444                (char *) _dwarf_p_get_alloc(dbg,
445                                            sizeof(Dwarf_Unsigned));
446            if (ptr == NULL) {
447                _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
448                return ((Dwarf_P_Fde) DW_DLV_BADADDR);
449            }
450            memcpy((void *) ptr, (const void *) &du, 8);
451            nbytes = 8;
452        }
453        break;
454
455    case DW_CFA_offset:
456        if (val1 <= MAX_6_BIT_VALUE) {
457            db = val1;
458            op |= db;
459            res = _dwarf_pro_encode_leb128_nm(val2, &nbytes,
460                                              buff1, sizeof(buff1));
461            if (res != DW_DLV_OK) {
462                _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
463                return ((Dwarf_P_Fde) DW_DLV_BADADDR);
464            }
465            ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes);
466            if (ptr == NULL) {
467                _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
468                return ((Dwarf_P_Fde) DW_DLV_BADADDR);
469            }
470            memcpy(ptr, buff1, nbytes);
471
472        } else {
473            op = DW_CFA_offset_extended;
474            goto two_leb;
475        }
476        break;
477    case DW_CFA_offset_extended_sf: /* DWARF3 */
478            signed_second = 1;
479            goto two_leb;
480    case DW_CFA_offset_extended:
481            goto two_leb;
482
483    case DW_CFA_undefined:
484    case DW_CFA_same_value:
485        goto one_leb;
486
487    case DW_CFA_val_offset:
488         goto two_leb;
489    case DW_CFA_val_offset_sf:
490         signed_second = 1;
491         goto two_leb;
492    case DW_CFA_def_cfa_sf:
493         signed_second = 1;
494         goto two_leb;
495    case DW_CFA_register:
496    case DW_CFA_def_cfa:
497    two_leb:
498        res = _dwarf_pro_encode_leb128_nm(val1, &nbytes1,
499                                          buff1, sizeof(buff1));
500        if (res != DW_DLV_OK) {
501            _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
502            return ((Dwarf_P_Fde) DW_DLV_BADADDR);
503        }
504        if (!signed_second) {
505                res = _dwarf_pro_encode_leb128_nm(val2, &nbytes2,
506                                              buff2, sizeof(buff2));
507        } else {
508            Dwarf_Signed val2s = val2;
509            res = _dwarf_pro_encode_signed_leb128_nm(val2s, &nbytes2,
510                                              buff2, sizeof(buff2));
511        }
512
513        res = _dwarf_pro_encode_leb128_nm(val2, &nbytes2,
514                                          buff2, sizeof(buff2));
515        if (res != DW_DLV_OK) {
516            _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
517            return ((Dwarf_P_Fde) DW_DLV_BADADDR);
518        }
519
520        ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes1 + nbytes2);
521        if (ptr == NULL) {
522            _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
523            return ((Dwarf_P_Fde) DW_DLV_BADADDR);
524        }
525        memcpy(ptr, buff1, nbytes1);
526        memcpy(ptr + nbytes1, buff2, nbytes2);
527        nbytes = nbytes1 + nbytes2;
528        break;
529
530    case DW_CFA_def_cfa_offset_sf: /* DWARF3 */
531        signed_first = 1;
532        goto one_leb;
533    case DW_CFA_def_cfa_register:
534    case DW_CFA_def_cfa_offset:
535    one_leb:
536        if(!signed_first) {
537            res = _dwarf_pro_encode_leb128_nm(val1, &nbytes,
538                                          buff1, sizeof(buff1));
539        } else {
540            Dwarf_Signed val1s = val1;
541            res = _dwarf_pro_encode_signed_leb128_nm(val1s, &nbytes,
542                                          buff1, sizeof(buff1));
543        }
544        if (res != DW_DLV_OK) {
545            _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
546            return ((Dwarf_P_Fde) DW_DLV_BADADDR);
547        }
548        ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes);
549        if (ptr == NULL) {
550            _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
551            return ((Dwarf_P_Fde) DW_DLV_BADADDR);
552        }
553        memcpy(ptr, buff1, nbytes);
554        break;
555    case DW_CFA_def_cfa_expression: /* DWARF3 */
556        /* FIXME: argument is dwarf expr, not handled yet. */
557    case DW_CFA_expression: /* DWARF3 */
558        /* First arg: ULEB reg num. 2nd arg dwarf expr in form block.
559           FIXME: not handled yet. */
560    case DW_CFA_val_expression: /* DWARF3f */
561        /* First arg: ULEB reg num. 2nd arg dwarf expr in form block.
562           FIXME: not handled yet. */
563    default:
564        _dwarf_p_error(dbg, error, DW_DLE_DEBUGFRAME_ERROR);
565        return ((Dwarf_P_Fde) DW_DLV_BADADDR);
566    }
567
568    curinst->dfp_opcode = op;
569    curinst->dfp_args = ptr;
570    curinst->dfp_nbytes = nbytes;
571    curinst->dfp_next = NULL;
572
573    _dwarf_pro_add_to_fde(fde, curinst);
574    return fde;
575}
576
577
578/*------------------------------------------------------------------------
579        Instructions are added to an fde in the form of a linked
580        list. This function manages the linked list.
581-------------------------------------------------------------------------*/
582void
583_dwarf_pro_add_to_fde(Dwarf_P_Fde fde, Dwarf_P_Frame_Pgm curinst)
584{
585    if (fde->fde_last_inst) {
586        fde->fde_last_inst->dfp_next = curinst;
587        fde->fde_last_inst = curinst;
588        fde->fde_n_inst++;
589        fde->fde_n_bytes +=
590            (long) (curinst->dfp_nbytes + sizeof(Dwarf_Ubyte));
591    } else {
592        fde->fde_last_inst = curinst;
593        fde->fde_inst = curinst;
594        fde->fde_n_inst = 1;
595        fde->fde_n_bytes =
596            (long) (curinst->dfp_nbytes + sizeof(Dwarf_Ubyte));
597    }
598}
599