xref: /illumos-gate/usr/src/lib/libdwarf/common/pro_reloc_symbolic.c (revision 4d9fdb46b215739778ebc12079842c9905586999)
1 /*
2 
3   Copyright (C) 2000,2004 Silicon Graphics, Inc.  All Rights Reserved.
4   Portions Copyright 2016 David Anderson.  All Rights Reserved.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of version 2.1 of the GNU Lesser General Public License
8   as published by the Free Software Foundation.
9 
10   This program is distributed in the hope that it would be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14   Further, this software is distributed without any warranty that it is
15   free of the rightful claim of any third person regarding infringement
16   or the like.  Any license provided herein, whether implied or
17   otherwise, applies only to this software file.  Patent licenses, if
18   any, provided herein do not apply to combinations of this program with
19   other software, or any other product whatsoever.
20 
21   You should have received a copy of the GNU Lesser General Public
22   License along with this program; if not, write the Free Software
23   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
24   USA.
25 
26 */
27 
28 #include "config.h"
29 #include "libdwarfdefs.h"
30 #include <stdio.h>
31 #ifdef HAVE_STRING_H
32 #include <string.h>
33 #endif /* HAVE_STRING_H */
34 #ifdef HAVE_STDDEF_H
35 #include <stddef.h>
36 #endif /* HAVE_STDDEF_H */
37 /*#include <elfaccess.h> */
38 #include "pro_incl.h"
39 #include "dwarf.h"
40 #include "libdwarf.h"
41 #include "pro_opaque.h"
42 #include "pro_error.h"
43 #include "pro_alloc.h"
44 #include "pro_section.h"
45 #include "pro_reloc.h"
46 #include "pro_reloc_symbolic.h"
47 
48 #ifndef SHT_REL
49 #define SHT_REL 9
50 #endif /* SHT_REL */
51 #ifndef SHN_UNDEF
52 #define SHN_UNDEF 0
53 #endif /* SHN_UNDEF */
54 
55 /*  Return DW_DLV_ERROR on malloc error.
56     Return DW_DLV_OK otherwise */
57 
58 int
_dwarf_pro_reloc_name_symbolic(Dwarf_P_Debug dbg,int base_sec_index,Dwarf_Unsigned offset,Dwarf_Unsigned symidx,enum Dwarf_Rel_Type type,int reltarget_length)59 _dwarf_pro_reloc_name_symbolic(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     /* get a slot, fill in the slot entry */
67     void *relrec_to_fill = 0;
68     int res = 0;
69     struct Dwarf_Relocation_Data_s *slotp;
70 
71     res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
72         &relrec_to_fill);
73     if (res != DW_DLV_OK)
74         return res;
75     slotp = (struct Dwarf_Relocation_Data_s *) relrec_to_fill;
76     slotp->drd_type = type;
77     slotp->drd_length = reltarget_length;
78     slotp->drd_offset = offset;
79     slotp->drd_symbol_index = symidx;
80     return DW_DLV_OK;
81 }
82 
83 
84 
85 /*  Return DW_DLV_ERROR on malloc error.
86     Return DW_DLV_OK otherwise */
87 int
_dwarf_pro_reloc_length_symbolic(Dwarf_P_Debug dbg,int base_sec_index,Dwarf_Unsigned offset,Dwarf_Unsigned start_symidx,Dwarf_Unsigned end_symidx,enum Dwarf_Rel_Type type,int reltarget_length)88 _dwarf_pro_reloc_length_symbolic(Dwarf_P_Debug dbg,
89     int base_sec_index,
90     Dwarf_Unsigned offset,  /* r_offset of reloc */
91     Dwarf_Unsigned start_symidx,
92     Dwarf_Unsigned end_symidx,
93     enum Dwarf_Rel_Type type,
94     int reltarget_length)
95 {
96     /* get a slot, fill in the slot entry */
97     void *relrec_to_fill = 0;
98     int res = 0;
99     struct Dwarf_Relocation_Data_s *slotp1 = 0;
100     struct Dwarf_Relocation_Data_s *slotp2 = 0;
101 
102     res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
103         &relrec_to_fill);
104     if (res != DW_DLV_OK)
105         return res;
106     slotp1 = (struct Dwarf_Relocation_Data_s *) relrec_to_fill;
107     res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
108         &relrec_to_fill);
109     if (res != DW_DLV_OK)
110         return res;
111     slotp2 = (struct Dwarf_Relocation_Data_s *) relrec_to_fill;
112 
113     /* ASSERT: type == dwarf_drt_first_of_length_type_pair */
114     slotp1->drd_type = type;
115     slotp1->drd_length = reltarget_length;
116     slotp1->drd_offset = offset;
117     slotp1->drd_symbol_index = start_symidx;
118 
119     slotp2->drd_type = dwarf_drt_second_of_length_pair;
120     slotp2->drd_length = reltarget_length;
121     slotp2->drd_offset = offset;
122     slotp2->drd_symbol_index = end_symidx;
123     return DW_DLV_OK;
124 }
125 
126 /*  Ensure each stream is a single buffer and
127     add that single buffer to the set of stream buffers.
128 
129     By creating a new buffer and copying if necessary.
130     (If > 1 block, reduce to 1 block)
131 
132     Free the input set of buffers if we consolidate.
133 
134     We pass back *new_sec_count as zero because we
135     are not creating normal sections for a .o, but
136     symbolic relocations, separately counted.
137 
138     Return -1 on error (malloc failure)
139 
140     Return DW_DLV_OK on success. Any other return indicates
141     malloc failed.  */
142 int
_dwarf_symbolic_relocs_to_disk(Dwarf_P_Debug dbg,Dwarf_Signed * new_sec_count)143 _dwarf_symbolic_relocs_to_disk(Dwarf_P_Debug dbg,
144     Dwarf_Signed * new_sec_count)
145 {
146     int i = 0;
147     Dwarf_Error error = 0;
148 
149     for (i = 0; i < NUM_DEBUG_SECTIONS; ++i) {
150         int sec_index = 0;
151         Dwarf_P_Per_Reloc_Sect p_reloc = dbg->de_reloc_sect + i;
152         unsigned long ct = p_reloc->pr_reloc_total_count;
153         int err = 0;
154         if (ct == 0) {
155             /*  No relocations in here. Nothing to do. */
156             continue;
157         }
158 
159         /* total_size = ct *len; */
160         sec_index = p_reloc->pr_sect_num_of_reloc_sect;
161         if (sec_index == 0) {
162             /*  sec_index zero means we have not processed this
163                 section of relocations yet. */
164             /*  Call de_callback_func
165                 getting section number of reloc section. */
166             int rel_section_index = 0;
167             Dwarf_Unsigned name_idx = 0;
168 
169             /*  This is a bit of a fake, as we do not really have true
170                 elf sections at all. Just the data such might contain.
171                 But this lets the caller eventually link things
172                 together: without this call we would not know what rel
173                 data goes with what section when we are asked for the
174                 real arrays. */
175 
176             if (dbg->de_callback_func) {
177                 /*  For symbolic relocations de_callback_func
178                     may well return 0.  */
179                 rel_section_index =
180                     dbg->de_callback_func(_dwarf_rel_section_names[i],
181                         dbg->de_relocation_record_size,
182                         /* type */ SHT_REL,
183                         /* flags */ 0,
184                         /* link to symtab, which we cannot
185                             know */ SHN_UNDEF,
186                         /* sec rels apply to */
187                         dbg->de_elf_sects[i],
188                         &name_idx,
189                         dbg->de_user_data,&err);
190             }
191             if (rel_section_index == -1) {
192                 {
193                     _dwarf_p_error(dbg, &error, DW_DLE_ELF_SECT_ERR);
194                     return (DW_DLV_ERROR);
195                 }
196             }
197             p_reloc->pr_sect_num_of_reloc_sect = rel_section_index;
198         }
199 
200 
201         /*  If pr_block_count 0 or 1 then the blocks are
202             an array (with 0 or 1 entries) so we'll just
203             return to the for loop. No more work to do here.  */
204         if (p_reloc->pr_block_count < 2) {
205             continue;
206         }
207         {
208             /*  Since more than one relocation on the section
209                 we now convert the list of relocation blocks
210                 into a proper array of blocks. */
211             struct Dwarf_P_Relocation_Block_s *new_blk = 0;
212             struct Dwarf_P_Relocation_Block_s *p_blk = 0;
213             Dwarf_Small *data = 0;
214             int res = 0;
215 
216             p_blk = p_reloc->pr_first_block;
217             /* Do not zero pr_sect_num_of_reloc_sect */
218             p_reloc->pr_reloc_total_count = 0;
219             p_reloc->pr_first_block = 0;
220             p_reloc->pr_last_block = 0;
221             p_reloc->pr_block_count = 0;
222             /*  Now we know a number making a single
223                 array. Replaces DEFAULT_SLOTS_PER_BLOCK */
224             p_reloc->pr_slots_per_block_to_alloc = ct;
225 
226             /*  Creating new single block for all 'ct' entries.
227                 Assigns a pointer value to pr_first_block
228                 (which means our p_reloc).
229                 It updates p_reloc->pr_first_block */
230             res = _dwarf_pro_pre_alloc_specific_reloc_slots(dbg,
231                 p_reloc,ct);
232             if (res != DW_DLV_OK) {
233                 return res;
234             }
235 
236             new_blk = p_reloc->pr_first_block;
237             data = (Dwarf_Small *) new_blk->rb_data;
238 
239             /*  The following loop does the consolidation to a single
240                 block and frees the input block(s).
241                 p_blk points to the old singly-linked-list
242                     and is the
243                     only access to that list.
244                 data is a pointer to the new array of ct entries
245                 which is our target(destination) of the copies.
246                 */
247             do {
248                 struct Dwarf_P_Relocation_Block_s *p_blk_last = 0;
249                 /*  len identifies the data in all the slots
250                     in use in this block. */
251                 unsigned long len =
252                     p_blk->rb_where_to_add_next - p_blk->rb_data;
253                 memcpy(data, p_blk->rb_data, len);
254                 data += len;
255                 p_blk_last = p_blk;
256                 p_blk = p_blk->rb_next;
257                 _dwarf_p_dealloc(dbg, (Dwarf_Small *) p_blk_last);
258             } while (p_blk);
259             /*  ASSERT: the dangling p_blk list all dealloc'd
260                 which is really a no-op, all deallocations
261                 take place at producer_finish().  */
262             /* ASSERT: sum of len copied == total_size */
263             new_blk->rb_next_slot_to_use = ct;
264             new_blk->rb_where_to_add_next = (char *) data;
265             p_reloc->pr_reloc_total_count = ct;
266 
267             /*  Have now created a single block, but no
268                 change in slots used (pr_reloc_total_count) */
269         }
270     }
271     /*  There is no section data with symbolic,
272         so there is no count. */
273     *new_sec_count = 0;
274     return DW_DLV_OK;
275 }
276