1/*
2  Copyright (C) 2000,2004 Silicon Graphics, Inc.  All Rights Reserved.
3  Portions Copyright 2008-2016 David Anderson, 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., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
23  USA.
24
25*/
26
27#include "config.h"
28#include "libdwarfdefs.h"
29#include <stdio.h>
30#ifdef HAVE_STRING_H
31#include <string.h>
32#endif /* HAVE_STRING_H */
33#ifdef HAVE_STDDEF_H
34#include <stddef.h>
35#endif /* HAVE_STDDEF_H */
36#include "pro_incl.h"
37#include "dwarf.h"
38#include "libdwarf.h"
39#include "pro_opaque.h"
40#include "pro_error.h"
41#include "pro_alloc.h"
42#include "pro_reloc.h"
43
44
45/*  Do initial alloc of newslots slots.
46    Fails only if malloc fails.
47
48    Supposed to be called before any relocs allocated.
49    Ignored if after any allocated.
50
51    Part of an optimization, so that for a known 'newslots'
52    relocations count we can preallocate the right size block.
53    Called from just 2 places.
54
55    We use 'slots' so we don't have to do a new
56    allocation for every relocation, just a new
57    allocation every n slots. slots_in_block.
58
59    returns DW_DLV_OK or  DW_DLV_ERROR
60*/
61int
62_dwarf_pro_pre_alloc_specific_reloc_slots(Dwarf_P_Debug dbg,
63    Dwarf_P_Per_Reloc_Sect prel,
64    Dwarf_Unsigned newslots)
65{
66    unsigned long len = 0;
67    struct Dwarf_P_Relocation_Block_s *data = 0;
68    unsigned long slots_in_blk = (unsigned long) newslots;
69    unsigned long rel_rec_size = dbg->de_relocation_record_size;
70
71    if (prel->pr_first_block) {
72        return DW_DLV_OK;       /* do nothing */
73    }
74
75    len = sizeof(struct Dwarf_P_Relocation_Block_s) +
76        slots_in_blk * rel_rec_size;
77    data = (struct Dwarf_P_Relocation_Block_s *)
78        _dwarf_p_get_alloc(dbg, len);
79    if (!data) {
80        return DW_DLV_ERROR;
81    }
82    data->rb_slots_in_block = slots_in_blk;     /* could use default
83        here, as fallback in case our origininal
84        estimate wrong. When we call this we
85        presumably know what we are doing, so
86        keep this count for now */
87    data->rb_next_slot_to_use = 0;
88    data->rb_where_to_add_next =
89        ((char *) data) + sizeof(struct Dwarf_P_Relocation_Block_s);
90    data->rb_data = data->rb_where_to_add_next;
91
92    prel->pr_first_block = data;
93    prel->pr_last_block = data;
94    prel->pr_block_count = 1;
95    return DW_DLV_OK;
96}
97
98
99/*Do alloc of slots.
100  Fails only if malloc fails.
101
102  Only allocator used.
103
104  returns DW_DLV_OK or  DW_DLV_ERROR
105*/
106int
107_dwarf_pro_alloc_reloc_slots(Dwarf_P_Debug dbg, int rel_sec_index)
108{
109    unsigned long len = 0;
110    struct Dwarf_P_Relocation_Block_s *data = 0;
111    Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[rel_sec_index];
112    unsigned long slots_in_blk = prel->pr_slots_per_block_to_alloc;
113    unsigned long rel_rec_size = dbg->de_relocation_record_size;
114
115    len = sizeof(struct Dwarf_P_Relocation_Block_s) +
116        slots_in_blk * rel_rec_size;
117
118    data = (struct Dwarf_P_Relocation_Block_s *)
119        _dwarf_p_get_alloc(dbg, len);
120    if (!data) {
121        return DW_DLV_ERROR;
122    }
123
124    if (prel->pr_first_block) {
125        prel->pr_last_block->rb_next = data;
126        prel->pr_last_block = data;
127        prel->pr_block_count += 1;
128    } else {
129        prel->pr_first_block = data;
130        prel->pr_last_block = data;
131        prel->pr_block_count = 1;
132    }
133    data->rb_slots_in_block = slots_in_blk;
134    data->rb_next_slot_to_use = 0;
135    data->rb_where_to_add_next =
136        ((char *) data) + sizeof(struct Dwarf_P_Relocation_Block_s);
137    data->rb_data = data->rb_where_to_add_next;
138    return DW_DLV_OK;
139
140}
141
142/*  Reserve a slot. return DW_DLV_OK if succeeds.
143
144    Return DW_DLV_ERROR if fails (malloc error).
145
146    Use the relrec_to_fill to pass back a pointer to
147    a slot space to use.  */
148int
149_dwarf_pro_reloc_get_a_slot(Dwarf_P_Debug dbg,
150    int base_sec_index, void **relrec_to_fill)
151{
152    struct Dwarf_P_Relocation_Block_s *data = 0;
153    Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[base_sec_index];
154    unsigned long rel_rec_size = dbg->de_relocation_record_size;
155
156    char *ret_addr = 0;
157
158    data = prel->pr_last_block;
159    if ((data == 0) ||
160        (data->rb_next_slot_to_use >= data->rb_slots_in_block)) {
161        int res;
162
163        res = _dwarf_pro_alloc_reloc_slots(dbg, base_sec_index);
164        if (res != DW_DLV_OK) {
165            return res;
166        }
167    }
168
169    data = prel->pr_last_block;
170    /* now we have an empty slot */
171    ret_addr = data->rb_where_to_add_next;
172    data->rb_where_to_add_next += rel_rec_size;
173    data->rb_next_slot_to_use += 1;
174    prel->pr_reloc_total_count += 1;
175    *relrec_to_fill = (void *) ret_addr;
176    return DW_DLV_OK;
177
178}
179
180/*
181    On success  returns count of
182    .rel.* sections that are symbolic
183    thru count_of_relocation_sections.
184
185    On success, returns DW_DLV_OK.
186
187    If this is not a 'symbolic' run, returns
188    DW_DLV_NO_ENTRY.
189
190    No errors are possible.
191*/
192/*ARGSUSED*/
193int
194dwarf_get_relocation_info_count(Dwarf_P_Debug dbg,
195    Dwarf_Unsigned *
196    count_of_relocation_sections,
197    int *drd_buffer_version,
198    UNUSEDARG Dwarf_Error * error)
199{
200    if (dbg->de_flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
201        int i = 0;
202        unsigned int count = 0;
203
204        for (i = 0; i < NUM_DEBUG_SECTIONS; ++i) {
205            if (dbg->de_reloc_sect[i].pr_reloc_total_count > 0) {
206                ++count;
207            }
208        }
209        *count_of_relocation_sections = (Dwarf_Unsigned) count;
210        *drd_buffer_version = DWARF_DRD_BUFFER_VERSION;
211        return DW_DLV_OK;
212    }
213    /*  Reset to start at beginning of reloc groups. */
214    dbg->de_reloc_next_to_return = 0;
215    return DW_DLV_NO_ENTRY;
216}
217
218int
219dwarf_get_relocation_info(Dwarf_P_Debug dbg,
220    Dwarf_Signed * elf_section_index,
221    Dwarf_Signed * elf_section_index_link,
222    Dwarf_Unsigned * relocation_buffer_count,
223    Dwarf_Relocation_Data * reldata_buffer,
224    Dwarf_Error * error)
225{
226    int next = dbg->de_reloc_next_to_return;
227
228    if (dbg->de_flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
229        int i = 0;
230
231        for (i = next; i < NUM_DEBUG_SECTIONS; ++i) {
232            /*  de_reloc_sect[] and de_elf_sects[] are
233                in direct parallel. */
234            Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[i];
235            int elf_sect_num =  dbg->de_elf_sects[i];
236
237            if (prel->pr_reloc_total_count > 0) {
238                /*  Set up 'next' for subsequent call to
239                    dwarf_get_relocation_info(). */
240                dbg->de_reloc_next_to_return = i + 1;
241
242                /* ASSERT: prel->pr_block_count == 1 */
243                *elf_section_index = prel->pr_sect_num_of_reloc_sect;
244
245                /*  Elf sec num in generated elf */
246                *elf_section_index_link = elf_sect_num;
247
248                *relocation_buffer_count = prel->pr_reloc_total_count;
249                *reldata_buffer = (Dwarf_Relocation_Data)
250                    (prel->pr_first_block->rb_data);
251                return DW_DLV_OK;
252            }
253        }
254        DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, DW_DLV_ERROR);
255    }
256    return DW_DLV_NO_ENTRY;
257}
258