xref: /illumos-gate/usr/src/lib/libdwarf/common/pro_reloc_stream.c (revision d49945110829673d27d215f4db010ac1d22a68de)
1 /*
2 
3   Copyright (C) 2000,2001,2004 Silicon Graphics, Inc.  All Rights Reserved.
4   Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
5   Portions Copyright 2008-2010 David Anderson, Inc. All rights reserved.
6 
7   This program is free software; you can redistribute it and/or modify it
8   under the terms of version 2.1 of the GNU Lesser General Public License
9   as published by the Free Software Foundation.
10 
11   This program is distributed in the hope that it would be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15   Further, this software is distributed without any warranty that it is
16   free of the rightful claim of any third person regarding infringement
17   or the like.  Any license provided herein, whether implied or
18   otherwise, applies only to this software file.  Patent licenses, if
19   any, provided herein do not apply to combinations of this program with
20   other software, or any other product whatsoever.
21 
22   You should have received a copy of the GNU Lesser General Public
23   License along with this program; if not, write the Free Software
24   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
25   USA.
26 
27   Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
28   Mountain View, CA 94043, or:
29 
30   http://www.sgi.com
31 
32   For further information regarding this notice, see:
33 
34   http://oss.sgi.com/projects/GenInfo/NoticeExplan
35 
36 */
37 
38 
39 
40 #include "config.h"
41 #include "libdwarfdefs.h"
42 #include <stdio.h>
43 #include <string.h>
44 #ifdef HAVE_ELFACCESS_H
45 #include <elfaccess.h>
46 #else
47 /* Set r_info  as defined by ELF generic ABI */
48 #define Set_REL32_info(r,s,t) ((r).r_info = ELF32_R_INFO(s,t))
49 #define Set_REL64_info(r,s,t) ((r).r_info = ELF64_R_INFO(s,t))
50 #endif
51 #include "pro_incl.h"
52 #include "pro_section.h"
53 #include "pro_reloc.h"
54 #include "pro_reloc_stream.h"
55 
56 /*
57         Return DW_DLV_ERROR on malloc error or reltarget_length error.
58         Return DW_DLV_OK otherwise
59 
60 
61 
62 */
63  /*ARGSUSED*/ int
64 _dwarf_pro_reloc_name_stream64(Dwarf_P_Debug dbg,
65     int base_sec_index,
66     Dwarf_Unsigned offset,      /* r_offset of reloc */
67     Dwarf_Unsigned symidx,
68     enum Dwarf_Rel_Type type,
69     int reltarget_length)
70 {
71 #if HAVE_ELF64_GETEHDR
72     REL64 *elf64_reloc = 0;
73     void *relrec_to_fill = 0;
74     int res = 0;
75     int rel_type = 0;
76 
77     res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
78                                       &relrec_to_fill);
79     if (res != DW_DLV_OK)
80         return res;
81 
82 
83     if (type == dwarf_drt_data_reloc) {
84         if (reltarget_length == dbg->de_offset_size) {
85             rel_type = dbg->de_offset_reloc;
86         } else if (reltarget_length == dbg->de_pointer_size) {
87             rel_type = dbg->de_ptr_reloc;
88         } else {
89             return DW_DLV_ERROR;
90         }
91     } else if (type == dwarf_drt_segment_rel) {
92         rel_type = dbg->de_exc_reloc;
93     } else {
94         /* We are in trouble: improper use of stream relocations.
95            Someone else will diagnose */
96         rel_type = 0;
97     }
98 
99     elf64_reloc = (REL64 *)relrec_to_fill;
100     elf64_reloc->r_offset = offset;
101     Set_REL64_info(*elf64_reloc, symidx, rel_type);
102     return DW_DLV_OK;
103 #else /* !HAVE_ELF64_GETEHDR */
104     return DW_DLV_ERROR;
105 #endif /* #if HAVE_ELF64_GETEHDR */
106 }
107 
108 /*
109         Return DW_DLV_ERROR on malloc error or reltarget_length error.
110         Return DW_DLV_OK otherwise
111         a binary reloc: 32bit ABI
112 */
113 int
114 _dwarf_pro_reloc_name_stream32(Dwarf_P_Debug dbg, int base_sec_index,
115     Dwarf_Unsigned offset,      /* r_offset of reloc */
116     Dwarf_Unsigned symidx,
117     enum Dwarf_Rel_Type type,
118     int reltarget_length)
119 {
120     REL32 *elf32_reloc = 0;
121     void *relrec_to_fill = 0;
122     int res = 0;
123     int rel_type = 0;
124 
125     res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
126                                       &relrec_to_fill);
127     if (res != DW_DLV_OK)
128         return res;
129     if (type == dwarf_drt_data_reloc) {
130         if (reltarget_length == dbg->de_offset_size) {
131             rel_type = dbg->de_offset_reloc;
132         } else if (reltarget_length == dbg->de_pointer_size) {
133             rel_type = dbg->de_ptr_reloc;
134         } else {
135             return DW_DLV_ERROR;
136         }
137     } else if (type == dwarf_drt_segment_rel) {
138         rel_type = dbg->de_exc_reloc;
139     } else {
140         /* We are in trouble: improper use of stream relocations.
141            Someone else will diagnose */
142         rel_type = 0;
143     }
144 
145     elf32_reloc = (REL32*)relrec_to_fill;
146     elf32_reloc->r_offset = (Elf32_Addr) offset;
147     Set_REL32_info(*elf32_reloc, (Dwarf_Word) symidx, rel_type);
148     return DW_DLV_OK;
149 
150     /* get a slot, fill in the slot entry */
151 }
152 
153 
154 
155 /*
156         Return DW_DLV_OK.
157         Never can really do anything: lengths cannot
158         be represented as end-start in a stream.
159 
160 */
161  /*ARGSUSED*/ int
162 _dwarf_pro_reloc_length_stream(Dwarf_P_Debug dbg,
163     int base_sec_index,
164     Dwarf_Unsigned offset,    /* r_offset of reloc */
165     Dwarf_Unsigned start_symidx,
166     Dwarf_Unsigned end_symidx,
167     enum Dwarf_Rel_Type type,
168     int reltarget_length)
169 {
170     /* get a slot, fill in the slot entry */
171     return DW_DLV_OK;
172 }
173 
174 
175 /*
176         Ensure each stream is a single buffer and
177         add that single buffer to the set of stream buffers.
178 
179         By creating a new buffer and copying if necessary.
180 
181         Free the input set of buffers if we consolidate.
182         Return -1 on error (malloc failure)
183 
184 
185         Return DW_DLV_OK on success. Any other return indicates
186         malloc failed.
187 
188 */
189 int
190 _dwarf_stream_relocs_to_disk(Dwarf_P_Debug dbg,
191     Dwarf_Signed * new_sec_count)
192 {
193     unsigned long total_size = 0;
194     Dwarf_Small *data = 0;
195     int sec_index = 0;
196     unsigned long i = 0;
197     Dwarf_Error err = 0;
198     Dwarf_Error *error = &err;
199 
200     Dwarf_Signed sec_count = 0;
201 
202     Dwarf_P_Per_Reloc_Sect p_reloc = &dbg->de_reloc_sect[0];
203 
204     for (i = 0; i < NUM_DEBUG_SECTIONS; ++i, ++p_reloc) {
205         unsigned long ct = p_reloc->pr_reloc_total_count;
206         unsigned len = 0;
207         struct Dwarf_P_Relocation_Block_s *p_blk = 0;
208         struct Dwarf_P_Relocation_Block_s *p_blk_last = 0;
209         Dwarf_P_Per_Reloc_Sect prb = 0;
210 
211         if (ct == 0) {
212             continue;
213         }
214         prb = &dbg->de_reloc_sect[i];
215         len = dbg->de_relocation_record_size;
216         ++sec_count;
217 
218         total_size = ct * len;
219         sec_index = prb->pr_sect_num_of_reloc_sect;
220         if (sec_index == 0) {
221             /* Call de_callback_func or de_callback_func_b, getting
222                section number of reloc section. */
223             int rel_section_index = 0;
224             Dwarf_Unsigned name_idx = 0;
225             int int_name = 0;
226             int err = 0;
227 
228             if (dbg->de_callback_func_b) {
229                 rel_section_index =
230                     dbg->de_callback_func_b(_dwarf_rel_section_names[i],
231                                    /* size */
232                                    dbg->de_relocation_record_size,
233                                    /* type */ SHT_REL,
234                                    /* flags */ 0,
235                                    /* link to symtab, which we cannot
236                                       know */ 0,
237                                    /* info == link to sec rels apply to
238                                     */
239                                    dbg->de_elf_sects[i],
240                                    &name_idx, &err);
241             } else {
242                 rel_section_index =
243                     dbg->de_callback_func(_dwarf_rel_section_names[i],
244                                  /* size */
245                                  dbg->de_relocation_record_size,
246                                  /* type */ SHT_REL,
247                                  /* flags */ 0,
248                                  /* link to symtab, which we cannot
249                                     know */ 0,
250                                  /* info == link to sec rels apply to */
251                                  dbg->de_elf_sects[i], &int_name, &err);
252                 name_idx = int_name;
253             }
254             if (rel_section_index == -1) {
255                 {
256                     _dwarf_p_error(dbg, error, DW_DLE_ELF_SECT_ERR);
257                     return (DW_DLV_ERROR);
258                 }
259 
260             }
261             prb->pr_sect_num_of_reloc_sect = rel_section_index;
262             sec_index = rel_section_index;
263         }
264         GET_CHUNK(dbg, sec_index, data, total_size, &err);
265         p_blk = p_reloc->pr_first_block;
266 
267         /* following loop executes at least once. Effects the
268            consolidation to a single block or, if already a single
269            block, simply copies to the output buffer. And frees the
270            input block. The new block is in the de_debug_sects list. */
271         while (p_blk) {
272 
273             unsigned long len =
274                 p_blk->rb_where_to_add_next - p_blk->rb_data;
275 
276             memcpy(data, p_blk->rb_data, len);
277 
278 
279             data += len;
280 
281             p_blk_last = p_blk;
282             p_blk = p_blk->rb_next;
283 
284             _dwarf_p_dealloc(dbg, (Dwarf_Small *) p_blk_last);
285         }
286         /* ASSERT: sum of len copied == total_size */
287 
288         /*
289            We have copied the input, now drop the pointers to it. For
290            debugging, leave the other data untouched. */
291         p_reloc->pr_first_block = 0;
292         p_reloc->pr_last_block = 0;
293     }
294 
295     *new_sec_count = sec_count;
296     return DW_DLV_OK;
297 }
298