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., 59 Temple Place - Suite 330, Boston MA 02111-1307,
23  USA.
24
25  Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
26  Mountain View, CA 94043, or:
27
28  http://www.sgi.com
29
30  For further information regarding this notice, see:
31
32  http://oss.sgi.com/projects/GenInfo/NoticeExplan
33
34*/
35
36
37
38#include "config.h"
39#include "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 functions 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
149    curfde = dbg->de_last_fde;
150    if (curfde == NULL) {
151	dbg->de_frame_fdes = fde;
152	dbg->de_last_fde = fde;
153	dbg->de_n_fde = 1;
154    } else {
155	curfde->fde_next = fde;
156	dbg->de_last_fde = fde;
157	dbg->de_n_fde++;
158    }
159    return dbg->de_n_fde;
160}
161
162/*-------------------------------------------------------------------------
163	This functions adds information to an fde. The fde is
164	linked into the linked list of fde's maintained in the Dwarf_P_Debug
165	structure.
166	dbg: The debug descriptor.
167	fde: The fde to be added.
168	die: subprogram/function die corresponding to this fde
169	cie: cie referred to by this fde, obtained from call to
170	    add_frame_cie() routine.
171	virt_addr: beginning address
172	code_len: length of code reps by the fde
173	symidx: The symbol id of the symbol wrt to which relocation needs
174		to be performed for 'virt_addr'.
175	offset_into_exception_tables: The start of exception tables for
176		this function (indicated as an offset into the exception
177		tables). A value of -1 indicates that there is no exception
178		table entries associated with this function.
179	exception_table_symbol: The symbol id of the section for exception
180		tables wrt to which the offset_into_exception_tables will
181		be relocated.
182--------------------------------------------------------------------------*/
183Dwarf_Unsigned
184dwarf_add_frame_info(Dwarf_P_Debug dbg,
185		     Dwarf_P_Fde fde,
186		     Dwarf_P_Die die,
187		     Dwarf_Unsigned cie,
188		     Dwarf_Unsigned virt_addr,
189		     Dwarf_Unsigned code_len,
190		     Dwarf_Unsigned symidx,
191		     Dwarf_Signed offset_into_exception_tables,
192		     Dwarf_Unsigned exception_table_symbol,
193		     Dwarf_Error * error)
194{
195
196    return dwarf_add_frame_info_b(dbg, fde, die, cie, virt_addr,
197				  code_len, symidx,
198				  /* end_symbol */ 0,
199				  /* offset_from_end */ 0,
200				  offset_into_exception_tables,
201				  exception_table_symbol, error);
202
203}
204
205 /*ARGSUSED*/			/* pretend all args used */
206    Dwarf_Unsigned
207dwarf_add_frame_info_b(Dwarf_P_Debug dbg,
208		       Dwarf_P_Fde fde,
209		       Dwarf_P_Die die,
210		       Dwarf_Unsigned cie,
211		       Dwarf_Unsigned virt_addr,
212		       Dwarf_Unsigned code_len,
213		       Dwarf_Unsigned symidx,
214		       Dwarf_Unsigned end_symidx,
215		       Dwarf_Unsigned offset_from_end_symbol,
216		       Dwarf_Signed offset_into_exception_tables,
217		       Dwarf_Unsigned exception_table_symbol,
218		       Dwarf_Error * error)
219{
220    Dwarf_P_Fde curfde;
221
222    fde->fde_die = die;
223    fde->fde_cie = (long) cie;
224    fde->fde_initloc = virt_addr;
225    fde->fde_r_symidx = symidx;
226    fde->fde_addr_range = code_len;
227    fde->fde_offset_into_exception_tables =
228	offset_into_exception_tables;
229    fde->fde_exception_table_symbol = exception_table_symbol;
230    fde->fde_end_symbol_offset = offset_from_end_symbol;
231    fde->fde_end_symbol = end_symidx;
232
233
234    curfde = dbg->de_last_fde;
235    if (curfde == NULL) {
236	dbg->de_frame_fdes = fde;
237	dbg->de_last_fde = fde;
238	dbg->de_n_fde = 1;
239    } else {
240	curfde->fde_next = fde;
241	dbg->de_last_fde = fde;
242	dbg->de_n_fde++;
243    }
244    return dbg->de_n_fde;
245}
246
247
248/*-------------------------------------------------------------------
249	Create a new fde
250---------------------------------------------------------------------*/
251Dwarf_P_Fde
252dwarf_new_fde(Dwarf_P_Debug dbg, Dwarf_Error * error)
253{
254    Dwarf_P_Fde fde;
255
256    fde = (Dwarf_P_Fde)
257	_dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Fde_s));
258    if (fde == NULL) {
259	DWARF_P_DBG_ERROR(dbg, DW_DLE_FDE_ALLOC,
260			  (Dwarf_P_Fde) DW_DLV_BADADDR);
261    }
262    fde->fde_next = NULL;
263    fde->fde_inst = NULL;
264    fde->fde_n_inst = 0;
265    fde->fde_n_bytes = 0;
266    fde->fde_last_inst = NULL;
267    fde->fde_uwordb_size = dbg->de_offset_size;
268    return fde;
269}
270
271/*------------------------------------------------------------------------
272	Add cfe_offset instruction to fde
273-------------------------------------------------------------------------*/
274Dwarf_P_Fde
275dwarf_fde_cfa_offset(Dwarf_P_Fde fde,
276		     Dwarf_Unsigned reg,
277		     Dwarf_Signed offset, Dwarf_Error * error)
278{
279    Dwarf_Ubyte opc, regno;
280    char *ptr;
281    Dwarf_P_Frame_Pgm curinst;
282    int nbytes;
283    int res;
284    char buff1[ENCODE_SPACE_NEEDED];
285
286    curinst = (Dwarf_P_Frame_Pgm)
287	_dwarf_p_get_alloc(NULL, sizeof(struct Dwarf_P_Frame_Pgm_s));
288    if (curinst == NULL) {
289	DWARF_P_DBG_ERROR(NULL, DW_DLE_FPGM_ALLOC,
290			  (Dwarf_P_Fde) DW_DLV_BADADDR);
291    }
292    opc = DW_CFA_offset;
293    regno = reg;
294    if (regno & 0xc0) {
295	DWARF_P_DBG_ERROR(NULL, DW_DLE_REGNO_OVFL,
296			  (Dwarf_P_Fde) DW_DLV_BADADDR);
297    }
298    opc = opc | regno;		/* lower 6 bits are register number */
299    curinst->dfp_opcode = opc;
300    res = _dwarf_pro_encode_leb128_nm(offset, &nbytes,
301				      buff1, sizeof(buff1));
302    if (res != DW_DLV_OK) {
303	_dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
304	return ((Dwarf_P_Fde) DW_DLV_BADADDR);
305    }
306    ptr = (char *) _dwarf_p_get_alloc(NULL, nbytes);
307    if (ptr == NULL) {
308	_dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
309	return ((Dwarf_P_Fde) DW_DLV_BADADDR);
310    }
311    memcpy(ptr, buff1, nbytes);
312
313    curinst->dfp_args = ptr;
314    curinst->dfp_nbytes = nbytes;
315    curinst->dfp_next = NULL;
316
317    _dwarf_pro_add_to_fde(fde, curinst);
318    return fde;
319}
320
321/*
322    Generic routine to add opcode to fde instructions. val1 and
323    val2 are parameters whose interpretation depends on the 'op'.
324
325    This does not work properly for  DW_DLC_SYMBOLIC_RELOCATIONS
326    for DW_CFA_set_loc or DW_DVA_advance_loc* 'op', as
327    these ops normally are addresses or (DW_CFA_set_loc)
328    or code lengths (DW_DVA_advance_loc*) and such must be
329    represented with relocations and symbol indices for
330    DW_DLC_SYMBOLIC_RELOCATIONS.
331
332*/
333Dwarf_P_Fde
334dwarf_add_fde_inst(Dwarf_P_Fde fde,
335		   Dwarf_Small op,
336		   Dwarf_Unsigned val1,
337		   Dwarf_Unsigned val2, Dwarf_Error * error)
338{
339    Dwarf_P_Frame_Pgm curinst;
340    int nbytes, nbytes1, nbytes2;
341    Dwarf_Ubyte db;
342    Dwarf_Half dh;
343    Dwarf_Word dw;
344    Dwarf_Unsigned du;
345    char *ptr;
346    int res;
347    char buff1[ENCODE_SPACE_NEEDED];
348    char buff2[ENCODE_SPACE_NEEDED];
349
350
351    nbytes = 0;
352    ptr = NULL;
353    curinst = (Dwarf_P_Frame_Pgm)
354	_dwarf_p_get_alloc(NULL, sizeof(struct Dwarf_P_Frame_Pgm_s));
355    if (curinst == NULL) {
356	_dwarf_p_error(NULL, error, DW_DLE_FPGM_ALLOC);
357	return ((Dwarf_P_Fde) DW_DLV_BADADDR);
358    }
359
360    switch (op) {
361
362    case DW_CFA_advance_loc:
363	if (val1 <= 0x3f) {
364	    db = val1;
365	    op |= db;
366	}
367	/* test not portable FIX */
368	else if (val1 <= UCHAR_MAX) {
369	    op = DW_CFA_advance_loc1;
370	    db = val1;
371	    ptr = (char *) _dwarf_p_get_alloc(NULL, 1);
372	    if (ptr == NULL) {
373		_dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
374		return ((Dwarf_P_Fde) DW_DLV_BADADDR);
375	    }
376	    memcpy((void *) ptr, (const void *) &db, 1);
377	    nbytes = 1;
378	}
379	/* test not portable FIX */
380	else if (val1 <= USHRT_MAX) {
381	    op = DW_CFA_advance_loc2;
382	    dh = val1;
383	    ptr = (char *) _dwarf_p_get_alloc(NULL, 2);
384	    if (ptr == NULL) {
385		_dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
386		return ((Dwarf_P_Fde) DW_DLV_BADADDR);
387	    }
388	    memcpy((void *) ptr, (const void *) &dh, 2);
389	    nbytes = 2;
390	}
391	/* test not portable FIX */
392	else if (val1 <= ULONG_MAX) {
393	    op = DW_CFA_advance_loc4;
394	    dw = (Dwarf_Word) val1;
395	    ptr = (char *) _dwarf_p_get_alloc(NULL, 4);
396	    if (ptr == NULL) {
397		_dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
398		return ((Dwarf_P_Fde) DW_DLV_BADADDR);
399	    }
400	    memcpy((void *) ptr, (const void *) &dw, 4);
401	    nbytes = 4;
402	} else {
403	    op = DW_CFA_MIPS_advance_loc8;
404	    du = val1;
405	    ptr =
406		(char *) _dwarf_p_get_alloc(NULL,
407					    sizeof(Dwarf_Unsigned));
408	    if (ptr == NULL) {
409		_dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
410		return ((Dwarf_P_Fde) DW_DLV_BADADDR);
411	    }
412	    memcpy((void *) ptr, (const void *) &du, 8);
413	    nbytes = 8;
414	}
415	break;
416
417    case DW_CFA_offset:
418	if (val1 <= MAX_6_BIT_VALUE) {
419	    db = val1;
420	    op |= db;
421	    res = _dwarf_pro_encode_leb128_nm(val2, &nbytes,
422					      buff1, sizeof(buff1));
423	    if (res != DW_DLV_OK) {
424		_dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
425		return ((Dwarf_P_Fde) DW_DLV_BADADDR);
426	    }
427	    ptr = (char *) _dwarf_p_get_alloc(NULL, nbytes);
428	    if (ptr == NULL) {
429		_dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
430		return ((Dwarf_P_Fde) DW_DLV_BADADDR);
431	    }
432	    memcpy(ptr, buff1, nbytes);
433
434	} else {
435	    op = DW_CFA_offset_extended;
436
437	    res = _dwarf_pro_encode_leb128_nm(val1, &nbytes1,
438					      buff1, sizeof(buff1));
439	    if (res != DW_DLV_OK) {
440		_dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
441		return ((Dwarf_P_Fde) DW_DLV_BADADDR);
442	    }
443	    res = _dwarf_pro_encode_leb128_nm(val2, &nbytes2,
444					      buff2, sizeof(buff2));
445	    if (res != DW_DLV_OK) {
446		_dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
447		return ((Dwarf_P_Fde) DW_DLV_BADADDR);
448	    }
449	    ptr = (char *) _dwarf_p_get_alloc(NULL, nbytes1 + nbytes2);
450	    if (ptr == NULL) {
451		_dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
452		return ((Dwarf_P_Fde) DW_DLV_BADADDR);
453	    }
454	    memcpy(ptr, buff1, nbytes1);
455	    memcpy(ptr + nbytes1, buff2, nbytes2);
456	    nbytes = nbytes1 + nbytes2;
457	}
458	break;
459
460    case DW_CFA_undefined:
461    case DW_CFA_same_value:
462	res = _dwarf_pro_encode_leb128_nm(val1, &nbytes,
463					  buff1, sizeof(buff1));
464	if (res != DW_DLV_OK) {
465	    _dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
466	    return ((Dwarf_P_Fde) DW_DLV_BADADDR);
467	}
468	ptr = (char *) _dwarf_p_get_alloc(NULL, nbytes);
469	if (ptr == NULL) {
470	    _dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
471	    return ((Dwarf_P_Fde) DW_DLV_BADADDR);
472	}
473	memcpy(ptr, buff1, nbytes);
474	break;
475
476    case DW_CFA_register:
477    case DW_CFA_def_cfa:
478	res = _dwarf_pro_encode_leb128_nm(val1, &nbytes1,
479					  buff1, sizeof(buff1));
480	if (res != DW_DLV_OK) {
481	    _dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
482	    return ((Dwarf_P_Fde) DW_DLV_BADADDR);
483	}
484
485	res = _dwarf_pro_encode_leb128_nm(val2, &nbytes2,
486					  buff2, sizeof(buff2));
487	if (res != DW_DLV_OK) {
488	    _dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
489	    return ((Dwarf_P_Fde) DW_DLV_BADADDR);
490	}
491
492	ptr = (char *) _dwarf_p_get_alloc(NULL, nbytes1 + nbytes2);
493	if (ptr == NULL) {
494	    _dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
495	    return ((Dwarf_P_Fde) DW_DLV_BADADDR);
496	}
497	memcpy(ptr, buff1, nbytes1);
498	memcpy(ptr + nbytes1, buff2, nbytes2);
499	nbytes = nbytes1 + nbytes2;
500	break;
501
502    case DW_CFA_def_cfa_register:
503    case DW_CFA_def_cfa_offset:
504	res = _dwarf_pro_encode_leb128_nm(val1, &nbytes,
505					  buff1, sizeof(buff1));
506	if (res != DW_DLV_OK) {
507	    _dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
508	    return ((Dwarf_P_Fde) DW_DLV_BADADDR);
509	}
510	ptr = (char *) _dwarf_p_get_alloc(NULL, nbytes);
511	if (ptr == NULL) {
512	    _dwarf_p_error(NULL, error, DW_DLE_STRING_ALLOC);
513	    return ((Dwarf_P_Fde) DW_DLV_BADADDR);
514	}
515	memcpy(ptr, buff1, nbytes);
516	break;
517
518    default:
519	break;
520    }
521
522    curinst->dfp_opcode = op;
523    curinst->dfp_args = ptr;
524    curinst->dfp_nbytes = nbytes;
525    curinst->dfp_next = NULL;
526
527    _dwarf_pro_add_to_fde(fde, curinst);
528    return fde;
529}
530
531
532/*------------------------------------------------------------------------
533	instructions are added to fde in the form of a linked
534	list. This function manages the linked list
535-------------------------------------------------------------------------*/
536void
537_dwarf_pro_add_to_fde(Dwarf_P_Fde fde, Dwarf_P_Frame_Pgm curinst)
538{
539    if (fde->fde_last_inst) {
540	fde->fde_last_inst->dfp_next = curinst;
541	fde->fde_last_inst = curinst;
542	fde->fde_n_inst++;
543	fde->fde_n_bytes +=
544	    (long) (curinst->dfp_nbytes + sizeof(Dwarf_Ubyte));
545    } else {
546	fde->fde_last_inst = curinst;
547	fde->fde_inst = curinst;
548	fde->fde_n_inst = 1;
549	fde->fde_n_bytes =
550	    (long) (curinst->dfp_nbytes + sizeof(Dwarf_Ubyte));
551    }
552}
553