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