1/*
2
3  Copyright (C) 2000,2001,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#ifdef HAVE_ELFACCESS_H
43#include <elfaccess.h>
44#else
45/* Set r_info  as defined by ELF generic ABI */
46#define Set_REL32_info(r,s,t) ((r).r_info = ELF32_R_INFO(s,t))
47#define Set_REL64_info(r,s,t) ((r).r_info = ELF64_R_INFO(s,t))
48#endif
49#include "pro_incl.h"
50#include "pro_section.h"
51#include "pro_reloc.h"
52#include "pro_reloc_stream.h"
53
54/*
55	Return DW_DLV_ERROR on malloc error or reltarget_length error.
56	Return DW_DLV_OK otherwise
57
58
59
60*/
61 /*ARGSUSED*/ int
62_dwarf_pro_reloc_name_stream64(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset,	/* r_offset
63												   of
64												   reloc
65												 */
66			       Dwarf_Unsigned symidx,
67			       enum Dwarf_Rel_Type type,
68			       int reltarget_length)
69{
70#if HAVE_ELF64_GETEHDR
71    Elf64_Rel *elf64_reloc;
72    void *relrec_to_fill;
73    int res;
74    int rel_type;
75
76    res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
77				      &relrec_to_fill);
78    if (res != DW_DLV_OK)
79	return res;
80
81
82    if (type == dwarf_drt_data_reloc) {
83	if (reltarget_length == dbg->de_offset_size) {
84	    rel_type = dbg->de_offset_reloc;
85	} else if (reltarget_length == dbg->de_pointer_size) {
86	    rel_type = dbg->de_ptr_reloc;
87	} else {
88	    return DW_DLV_ERROR;
89	}
90    } else if (type == dwarf_drt_segment_rel) {
91	rel_type = dbg->de_exc_reloc;
92    } else {
93	/* We are in trouble: improper use of stream relocations.
94	   Someone else will diagnose */
95	rel_type = 0;
96    }
97
98    elf64_reloc = (Elf64_Rel *) relrec_to_fill;
99    elf64_reloc->r_offset = offset;
100    Set_REL64_info(*elf64_reloc, symidx, rel_type);
101    return DW_DLV_OK;
102#else /* !HAVE_ELF64_GETEHDR */
103    return DW_DLV_ERROR;
104#endif /* #if HAVE_ELF64_GETEHDR */
105}
106
107/*
108	Return DW_DLV_ERROR on malloc error or reltarget_length error.
109	Return DW_DLV_OK otherwise
110	a binary reloc: 32bit ABI
111*/
112int
113_dwarf_pro_reloc_name_stream32(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset,	/* r_offset
114												   of
115												   reloc
116												 */
117			       Dwarf_Unsigned symidx,
118			       enum Dwarf_Rel_Type type,
119			       int reltarget_length)
120{
121    Elf32_Rel *elf32_reloc;
122    void *relrec_to_fill;
123    int res;
124    int rel_type;
125
126    res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
127				      &relrec_to_fill);
128    if (res != DW_DLV_OK)
129	return res;
130    if (type == dwarf_drt_data_reloc) {
131	if (reltarget_length == dbg->de_offset_size) {
132	    rel_type = dbg->de_offset_reloc;
133	} else if (reltarget_length == dbg->de_pointer_size) {
134	    rel_type = dbg->de_ptr_reloc;
135	} else {
136	    return DW_DLV_ERROR;
137	}
138    } else if (type == dwarf_drt_segment_rel) {
139	rel_type = dbg->de_exc_reloc;
140    } else {
141	/* We are in trouble: improper use of stream relocations.
142	   Someone else will diagnose */
143	rel_type = 0;
144    }
145
146    elf32_reloc = (Elf32_Rel *) relrec_to_fill;
147    elf32_reloc->r_offset = (Elf32_Addr) offset;
148    Set_REL32_info(*elf32_reloc, (Dwarf_Word) symidx, rel_type);
149    return DW_DLV_OK;
150
151    /* get a slot, fill in the slot entry */
152}
153
154
155
156/*
157	Return DW_DLV_OK.
158	Never can really do anything: lengths cannot
159	be represented as end-start in a stream.
160
161*/
162 /*ARGSUSED*/ int
163_dwarf_pro_reloc_length_stream(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset,	/* r_offset
164												   of
165												   reloc
166												 */
167			       Dwarf_Unsigned start_symidx,
168			       Dwarf_Unsigned end_symidx,
169			       enum Dwarf_Rel_Type type,
170			       int reltarget_length)
171{
172    /* get a slot, fill in the slot entry */
173    return DW_DLV_OK;
174}
175
176
177/*
178        Ensure each stream is a single buffer and
179        add that single buffer to the set of stream buffers.
180
181	By creating a new buffer and copying if necessary.
182
183        Free the input set of buffers if we consolidate.
184        Return -1 on error (malloc failure)
185
186
187        Return DW_DLV_OK on success. Any other return indicates
188	malloc failed.
189
190*/
191int
192_dwarf_stream_relocs_to_disk(Dwarf_P_Debug dbg,
193			     Dwarf_Signed * new_sec_count)
194{
195    unsigned long total_size = 0;
196    Dwarf_Small *data;
197    int sec_index;
198    unsigned long i;
199    Dwarf_Error err;
200    Dwarf_Error *error = &err;
201
202    Dwarf_Signed sec_count = 0;
203
204    Dwarf_P_Per_Reloc_Sect p_reloc = &dbg->de_reloc_sect[0];
205
206    for (i = 0; i < NUM_DEBUG_SECTIONS; ++i, ++p_reloc) {
207	unsigned long ct = p_reloc->pr_reloc_total_count;
208	unsigned len;
209	struct Dwarf_P_Relocation_Block_s *p_blk;
210	struct Dwarf_P_Relocation_Block_s *p_blk_last;
211	Dwarf_P_Per_Reloc_Sect prb;
212
213	if (ct == 0) {
214	    continue;
215	}
216	prb = &dbg->de_reloc_sect[i];
217	len = dbg->de_relocation_record_size;
218	++sec_count;
219
220	total_size = ct * len;
221	sec_index = prb->pr_sect_num_of_reloc_sect;
222	if (sec_index == 0) {
223	    /* call de_func or de_func_b, getting section number of
224	       reloc sec */
225	    int rel_section_index;
226	    Dwarf_Unsigned name_idx;
227	    int int_name;
228	    int err;
229
230	    if (dbg->de_func_b) {
231		rel_section_index =
232		    dbg->de_func_b(_dwarf_rel_section_names[i],
233				   /* size */
234				   dbg->de_relocation_record_size,
235				   /* type */ SHT_REL,
236				   /* flags */ 0,
237				   /* link to symtab, which we cannot
238				      know */ 0,
239				   /* info == link to sec rels apply to
240				    */
241				   dbg->de_elf_sects[i],
242				   &name_idx, &err);
243	    } else {
244		rel_section_index =
245		    dbg->de_func(_dwarf_rel_section_names[i],
246				 /* size */
247				 dbg->de_relocation_record_size,
248				 /* type */ SHT_REL,
249				 /* flags */ 0,
250				 /* link to symtab, which we cannot
251				    know */ 0,
252				 /* info == link to sec rels apply to */
253				 dbg->de_elf_sects[i], &int_name, &err);
254		name_idx = int_name;
255	    }
256	    if (rel_section_index == -1) {
257		{
258		    _dwarf_p_error(dbg, error, DW_DLE_ELF_SECT_ERR);
259		    return (DW_DLV_ERROR);
260		}
261
262	    }
263	    prb->pr_sect_num_of_reloc_sect = rel_section_index;
264	    sec_index = rel_section_index;
265	}
266	GET_CHUNK(dbg, sec_index, data, total_size, &err);
267	p_blk = p_reloc->pr_first_block;
268
269	/* following loop executes at least once. Effects the
270	   consolidation to a single block or, if already a single
271	   block, simply copies to the output buffer. And frees the
272	   input block. The new block is in the de_debug_sects list. */
273	while (p_blk) {
274
275	    unsigned long len =
276		p_blk->rb_where_to_add_next - p_blk->rb_data;
277
278	    memcpy(data, p_blk->rb_data, len);
279
280
281	    data += len;
282
283	    p_blk_last = p_blk;
284	    p_blk = p_blk->rb_next;
285
286	    _dwarf_p_dealloc(dbg, (Dwarf_Small *) p_blk_last);
287	}
288	/* ASSERT: sum of len copied == total_size */
289
290	/*
291	   We have copied the input, now drop the pointers to it. For
292	   debugging, leave the other data untouched. */
293	p_reloc->pr_first_block = 0;
294	p_reloc->pr_last_block = 0;
295    }
296
297    *new_sec_count = sec_count;
298    return DW_DLV_OK;
299}
300