1 |
24 |
jeremybenn |
/* Routines to link ECOFF debugging information.
|
2 |
|
|
Copyright 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
|
3 |
225 |
jeremybenn |
2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
4 |
24 |
jeremybenn |
Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
|
5 |
|
|
|
6 |
|
|
This file is part of BFD, the Binary File Descriptor library.
|
7 |
|
|
|
8 |
|
|
This program is free software; you can redistribute it and/or modify
|
9 |
|
|
it under the terms of the GNU General Public License as published by
|
10 |
|
|
the Free Software Foundation; either version 3 of the License, or
|
11 |
|
|
(at your option) any later version.
|
12 |
|
|
|
13 |
|
|
This program is distributed in the hope that it will be useful,
|
14 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16 |
|
|
GNU General Public License for more details.
|
17 |
|
|
|
18 |
|
|
You should have received a copy of the GNU General Public License
|
19 |
|
|
along with this program; if not, write to the Free Software
|
20 |
|
|
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
21 |
|
|
MA 02110-1301, USA. */
|
22 |
|
|
|
23 |
|
|
#include "sysdep.h"
|
24 |
|
|
#include "bfd.h"
|
25 |
|
|
#include "bfdlink.h"
|
26 |
|
|
#include "libbfd.h"
|
27 |
|
|
#include "objalloc.h"
|
28 |
|
|
#include "aout/stab_gnu.h"
|
29 |
|
|
#include "coff/internal.h"
|
30 |
|
|
#include "coff/sym.h"
|
31 |
|
|
#include "coff/symconst.h"
|
32 |
|
|
#include "coff/ecoff.h"
|
33 |
|
|
#include "libcoff.h"
|
34 |
|
|
#include "libecoff.h"
|
35 |
|
|
|
36 |
|
|
static bfd_boolean ecoff_add_bytes
|
37 |
|
|
PARAMS ((char **buf, char **bufend, size_t need));
|
38 |
|
|
static struct bfd_hash_entry *string_hash_newfunc
|
39 |
|
|
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
|
40 |
|
|
const char *));
|
41 |
|
|
static void ecoff_align_debug
|
42 |
|
|
PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
|
43 |
|
|
const struct ecoff_debug_swap *swap));
|
44 |
|
|
static bfd_boolean ecoff_write_symhdr
|
45 |
|
|
PARAMS ((bfd *, struct ecoff_debug_info *, const struct ecoff_debug_swap *,
|
46 |
|
|
file_ptr where));
|
47 |
|
|
static int cmp_fdrtab_entry
|
48 |
|
|
PARAMS ((const PTR, const PTR));
|
49 |
|
|
static bfd_boolean mk_fdrtab
|
50 |
|
|
PARAMS ((bfd *, struct ecoff_debug_info * const,
|
51 |
|
|
const struct ecoff_debug_swap * const, struct ecoff_find_line *));
|
52 |
|
|
static long fdrtab_lookup
|
53 |
|
|
PARAMS ((struct ecoff_find_line *, bfd_vma));
|
54 |
|
|
static bfd_boolean lookup_line
|
55 |
|
|
PARAMS ((bfd *, struct ecoff_debug_info * const,
|
56 |
|
|
const struct ecoff_debug_swap * const, struct ecoff_find_line *));
|
57 |
|
|
|
58 |
|
|
/* Routines to swap auxiliary information in and out. I am assuming
|
59 |
|
|
that the auxiliary information format is always going to be target
|
60 |
|
|
independent. */
|
61 |
|
|
|
62 |
|
|
/* Swap in a type information record.
|
63 |
|
|
BIGEND says whether AUX symbols are big-endian or little-endian; this
|
64 |
|
|
info comes from the file header record (fh-fBigendian). */
|
65 |
|
|
|
66 |
|
|
void
|
67 |
|
|
_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern)
|
68 |
|
|
int bigend;
|
69 |
|
|
const struct tir_ext *ext_copy;
|
70 |
|
|
TIR *intern;
|
71 |
|
|
{
|
72 |
|
|
struct tir_ext ext[1];
|
73 |
|
|
|
74 |
|
|
*ext = *ext_copy; /* Make it reasonable to do in-place. */
|
75 |
|
|
|
76 |
|
|
/* now the fun stuff... */
|
77 |
|
|
if (bigend) {
|
78 |
|
|
intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG);
|
79 |
|
|
intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG);
|
80 |
|
|
intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_BIG)
|
81 |
|
|
>> TIR_BITS1_BT_SH_BIG;
|
82 |
|
|
intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG)
|
83 |
|
|
>> TIR_BITS_TQ4_SH_BIG;
|
84 |
|
|
intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG)
|
85 |
|
|
>> TIR_BITS_TQ5_SH_BIG;
|
86 |
|
|
intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG)
|
87 |
|
|
>> TIR_BITS_TQ0_SH_BIG;
|
88 |
|
|
intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG)
|
89 |
|
|
>> TIR_BITS_TQ1_SH_BIG;
|
90 |
|
|
intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG)
|
91 |
|
|
>> TIR_BITS_TQ2_SH_BIG;
|
92 |
|
|
intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG)
|
93 |
|
|
>> TIR_BITS_TQ3_SH_BIG;
|
94 |
|
|
} else {
|
95 |
|
|
intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE);
|
96 |
|
|
intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE);
|
97 |
|
|
intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE)
|
98 |
|
|
>> TIR_BITS1_BT_SH_LITTLE;
|
99 |
|
|
intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE)
|
100 |
|
|
>> TIR_BITS_TQ4_SH_LITTLE;
|
101 |
|
|
intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE)
|
102 |
|
|
>> TIR_BITS_TQ5_SH_LITTLE;
|
103 |
|
|
intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE)
|
104 |
|
|
>> TIR_BITS_TQ0_SH_LITTLE;
|
105 |
|
|
intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE)
|
106 |
|
|
>> TIR_BITS_TQ1_SH_LITTLE;
|
107 |
|
|
intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE)
|
108 |
|
|
>> TIR_BITS_TQ2_SH_LITTLE;
|
109 |
|
|
intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE)
|
110 |
|
|
>> TIR_BITS_TQ3_SH_LITTLE;
|
111 |
|
|
}
|
112 |
|
|
|
113 |
|
|
#ifdef TEST
|
114 |
|
|
if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
|
115 |
|
|
abort ();
|
116 |
|
|
#endif
|
117 |
|
|
}
|
118 |
|
|
|
119 |
|
|
/* Swap out a type information record.
|
120 |
|
|
BIGEND says whether AUX symbols are big-endian or little-endian; this
|
121 |
|
|
info comes from the file header record (fh-fBigendian). */
|
122 |
|
|
|
123 |
|
|
void
|
124 |
|
|
_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext)
|
125 |
|
|
int bigend;
|
126 |
|
|
const TIR *intern_copy;
|
127 |
|
|
struct tir_ext *ext;
|
128 |
|
|
{
|
129 |
|
|
TIR intern[1];
|
130 |
|
|
|
131 |
|
|
*intern = *intern_copy; /* Make it reasonable to do in-place. */
|
132 |
|
|
|
133 |
|
|
/* now the fun stuff... */
|
134 |
|
|
if (bigend) {
|
135 |
|
|
ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0)
|
136 |
|
|
| (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0)
|
137 |
|
|
| ((intern->bt << TIR_BITS1_BT_SH_BIG)
|
138 |
|
|
& TIR_BITS1_BT_BIG));
|
139 |
|
|
ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG)
|
140 |
|
|
& TIR_BITS_TQ4_BIG)
|
141 |
|
|
| ((intern->tq5 << TIR_BITS_TQ5_SH_BIG)
|
142 |
|
|
& TIR_BITS_TQ5_BIG));
|
143 |
|
|
ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG)
|
144 |
|
|
& TIR_BITS_TQ0_BIG)
|
145 |
|
|
| ((intern->tq1 << TIR_BITS_TQ1_SH_BIG)
|
146 |
|
|
& TIR_BITS_TQ1_BIG));
|
147 |
|
|
ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG)
|
148 |
|
|
& TIR_BITS_TQ2_BIG)
|
149 |
|
|
| ((intern->tq3 << TIR_BITS_TQ3_SH_BIG)
|
150 |
|
|
& TIR_BITS_TQ3_BIG));
|
151 |
|
|
} else {
|
152 |
|
|
ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0)
|
153 |
|
|
| (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0)
|
154 |
|
|
| ((intern->bt << TIR_BITS1_BT_SH_LITTLE)
|
155 |
|
|
& TIR_BITS1_BT_LITTLE));
|
156 |
|
|
ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE)
|
157 |
|
|
& TIR_BITS_TQ4_LITTLE)
|
158 |
|
|
| ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE)
|
159 |
|
|
& TIR_BITS_TQ5_LITTLE));
|
160 |
|
|
ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE)
|
161 |
|
|
& TIR_BITS_TQ0_LITTLE)
|
162 |
|
|
| ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE)
|
163 |
|
|
& TIR_BITS_TQ1_LITTLE));
|
164 |
|
|
ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE)
|
165 |
|
|
& TIR_BITS_TQ2_LITTLE)
|
166 |
|
|
| ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE)
|
167 |
|
|
& TIR_BITS_TQ3_LITTLE));
|
168 |
|
|
}
|
169 |
|
|
|
170 |
|
|
#ifdef TEST
|
171 |
|
|
if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
|
172 |
|
|
abort ();
|
173 |
|
|
#endif
|
174 |
|
|
}
|
175 |
|
|
|
176 |
|
|
/* Swap in a relative symbol record. BIGEND says whether it is in
|
177 |
|
|
big-endian or little-endian format.*/
|
178 |
|
|
|
179 |
|
|
void
|
180 |
|
|
_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern)
|
181 |
|
|
int bigend;
|
182 |
|
|
const struct rndx_ext *ext_copy;
|
183 |
|
|
RNDXR *intern;
|
184 |
|
|
{
|
185 |
|
|
struct rndx_ext ext[1];
|
186 |
|
|
|
187 |
|
|
*ext = *ext_copy; /* Make it reasonable to do in-place. */
|
188 |
|
|
|
189 |
|
|
/* now the fun stuff... */
|
190 |
|
|
if (bigend) {
|
191 |
|
|
intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG)
|
192 |
|
|
| ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG)
|
193 |
|
|
>> RNDX_BITS1_RFD_SH_BIG);
|
194 |
|
|
intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG)
|
195 |
|
|
<< RNDX_BITS1_INDEX_SH_LEFT_BIG)
|
196 |
|
|
| (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG)
|
197 |
|
|
| (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG);
|
198 |
|
|
} else {
|
199 |
|
|
intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE)
|
200 |
|
|
| ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE)
|
201 |
|
|
<< RNDX_BITS1_RFD_SH_LEFT_LITTLE);
|
202 |
|
|
intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE)
|
203 |
|
|
>> RNDX_BITS1_INDEX_SH_LITTLE)
|
204 |
|
|
| (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE)
|
205 |
|
|
| ((unsigned int) ext->r_bits[3]
|
206 |
|
|
<< RNDX_BITS3_INDEX_SH_LEFT_LITTLE);
|
207 |
|
|
}
|
208 |
|
|
|
209 |
|
|
#ifdef TEST
|
210 |
|
|
if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
|
211 |
|
|
abort ();
|
212 |
|
|
#endif
|
213 |
|
|
}
|
214 |
|
|
|
215 |
|
|
/* Swap out a relative symbol record. BIGEND says whether it is in
|
216 |
|
|
big-endian or little-endian format.*/
|
217 |
|
|
|
218 |
|
|
void
|
219 |
|
|
_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext)
|
220 |
|
|
int bigend;
|
221 |
|
|
const RNDXR *intern_copy;
|
222 |
|
|
struct rndx_ext *ext;
|
223 |
|
|
{
|
224 |
|
|
RNDXR intern[1];
|
225 |
|
|
|
226 |
|
|
*intern = *intern_copy; /* Make it reasonable to do in-place. */
|
227 |
|
|
|
228 |
|
|
/* now the fun stuff... */
|
229 |
|
|
if (bigend) {
|
230 |
|
|
ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG;
|
231 |
|
|
ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG)
|
232 |
|
|
& RNDX_BITS1_RFD_BIG)
|
233 |
|
|
| ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG)
|
234 |
|
|
& RNDX_BITS1_INDEX_BIG));
|
235 |
|
|
ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG;
|
236 |
|
|
ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG;
|
237 |
|
|
} else {
|
238 |
|
|
ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE;
|
239 |
|
|
ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE)
|
240 |
|
|
& RNDX_BITS1_RFD_LITTLE)
|
241 |
|
|
| ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE)
|
242 |
|
|
& RNDX_BITS1_INDEX_LITTLE));
|
243 |
|
|
ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE;
|
244 |
|
|
ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE;
|
245 |
|
|
}
|
246 |
|
|
|
247 |
|
|
#ifdef TEST
|
248 |
|
|
if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
|
249 |
|
|
abort ();
|
250 |
|
|
#endif
|
251 |
|
|
}
|
252 |
|
|
|
253 |
|
|
/* The minimum amount of data to allocate. */
|
254 |
|
|
#define ALLOC_SIZE (4064)
|
255 |
|
|
|
256 |
|
|
/* Add bytes to a buffer. Return success. */
|
257 |
|
|
|
258 |
|
|
static bfd_boolean
|
259 |
|
|
ecoff_add_bytes (buf, bufend, need)
|
260 |
|
|
char **buf;
|
261 |
|
|
char **bufend;
|
262 |
|
|
size_t need;
|
263 |
|
|
{
|
264 |
|
|
size_t have;
|
265 |
|
|
size_t want;
|
266 |
|
|
char *newbuf;
|
267 |
|
|
|
268 |
|
|
have = *bufend - *buf;
|
269 |
|
|
if (have > need)
|
270 |
|
|
want = ALLOC_SIZE;
|
271 |
|
|
else
|
272 |
|
|
{
|
273 |
|
|
want = need - have;
|
274 |
|
|
if (want < ALLOC_SIZE)
|
275 |
|
|
want = ALLOC_SIZE;
|
276 |
|
|
}
|
277 |
|
|
newbuf = (char *) bfd_realloc (*buf, (bfd_size_type) have + want);
|
278 |
|
|
if (newbuf == NULL)
|
279 |
|
|
return FALSE;
|
280 |
|
|
*buf = newbuf;
|
281 |
|
|
*bufend = *buf + have + want;
|
282 |
|
|
return TRUE;
|
283 |
|
|
}
|
284 |
|
|
|
285 |
|
|
/* We keep a hash table which maps strings to numbers. We use it to
|
286 |
|
|
map FDR names to indices in the output file, and to map local
|
287 |
|
|
strings when combining stabs debugging information. */
|
288 |
|
|
|
289 |
|
|
struct string_hash_entry
|
290 |
|
|
{
|
291 |
|
|
struct bfd_hash_entry root;
|
292 |
|
|
/* FDR index or string table offset. */
|
293 |
|
|
long val;
|
294 |
|
|
/* Next entry in string table. */
|
295 |
|
|
struct string_hash_entry *next;
|
296 |
|
|
};
|
297 |
|
|
|
298 |
|
|
struct string_hash_table
|
299 |
|
|
{
|
300 |
|
|
struct bfd_hash_table table;
|
301 |
|
|
};
|
302 |
|
|
|
303 |
|
|
/* Routine to create an entry in a string hash table. */
|
304 |
|
|
|
305 |
|
|
static struct bfd_hash_entry *
|
306 |
|
|
string_hash_newfunc (entry, table, string)
|
307 |
|
|
struct bfd_hash_entry *entry;
|
308 |
|
|
struct bfd_hash_table *table;
|
309 |
|
|
const char *string;
|
310 |
|
|
{
|
311 |
|
|
struct string_hash_entry *ret = (struct string_hash_entry *) entry;
|
312 |
|
|
|
313 |
|
|
/* Allocate the structure if it has not already been allocated by a
|
314 |
|
|
subclass. */
|
315 |
|
|
if (ret == (struct string_hash_entry *) NULL)
|
316 |
|
|
ret = ((struct string_hash_entry *)
|
317 |
|
|
bfd_hash_allocate (table, sizeof (struct string_hash_entry)));
|
318 |
|
|
if (ret == (struct string_hash_entry *) NULL)
|
319 |
|
|
return NULL;
|
320 |
|
|
|
321 |
|
|
/* Call the allocation method of the superclass. */
|
322 |
|
|
ret = ((struct string_hash_entry *)
|
323 |
|
|
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
|
324 |
|
|
|
325 |
|
|
if (ret)
|
326 |
|
|
{
|
327 |
|
|
/* Initialize the local fields. */
|
328 |
|
|
ret->val = -1;
|
329 |
|
|
ret->next = NULL;
|
330 |
|
|
}
|
331 |
|
|
|
332 |
|
|
return (struct bfd_hash_entry *) ret;
|
333 |
|
|
}
|
334 |
|
|
|
335 |
|
|
/* Look up an entry in an string hash table. */
|
336 |
|
|
|
337 |
|
|
#define string_hash_lookup(t, string, create, copy) \
|
338 |
|
|
((struct string_hash_entry *) \
|
339 |
|
|
bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
|
340 |
|
|
|
341 |
|
|
/* We can't afford to read in all the debugging information when we do
|
342 |
|
|
a link. Instead, we build a list of these structures to show how
|
343 |
|
|
different parts of the input file map to the output file. */
|
344 |
|
|
|
345 |
|
|
struct shuffle
|
346 |
|
|
{
|
347 |
|
|
/* The next entry in this linked list. */
|
348 |
|
|
struct shuffle *next;
|
349 |
|
|
/* The length of the information. */
|
350 |
|
|
unsigned long size;
|
351 |
|
|
/* Whether this information comes from a file or not. */
|
352 |
|
|
bfd_boolean filep;
|
353 |
|
|
union
|
354 |
|
|
{
|
355 |
|
|
struct
|
356 |
|
|
{
|
357 |
|
|
/* The BFD the data comes from. */
|
358 |
|
|
bfd *input_bfd;
|
359 |
|
|
/* The offset within input_bfd. */
|
360 |
|
|
file_ptr offset;
|
361 |
|
|
} file;
|
362 |
|
|
/* The data to be written out. */
|
363 |
|
|
PTR memory;
|
364 |
|
|
} u;
|
365 |
|
|
};
|
366 |
|
|
|
367 |
|
|
/* This structure holds information across calls to
|
368 |
|
|
bfd_ecoff_debug_accumulate. */
|
369 |
|
|
|
370 |
|
|
struct accumulate
|
371 |
|
|
{
|
372 |
|
|
/* The FDR hash table. */
|
373 |
|
|
struct string_hash_table fdr_hash;
|
374 |
|
|
/* The strings hash table. */
|
375 |
|
|
struct string_hash_table str_hash;
|
376 |
|
|
/* Linked lists describing how to shuffle the input debug
|
377 |
|
|
information into the output file. We keep a pointer to both the
|
378 |
|
|
head and the tail. */
|
379 |
|
|
struct shuffle *line;
|
380 |
|
|
struct shuffle *line_end;
|
381 |
|
|
struct shuffle *pdr;
|
382 |
|
|
struct shuffle *pdr_end;
|
383 |
|
|
struct shuffle *sym;
|
384 |
|
|
struct shuffle *sym_end;
|
385 |
|
|
struct shuffle *opt;
|
386 |
|
|
struct shuffle *opt_end;
|
387 |
|
|
struct shuffle *aux;
|
388 |
|
|
struct shuffle *aux_end;
|
389 |
|
|
struct shuffle *ss;
|
390 |
|
|
struct shuffle *ss_end;
|
391 |
|
|
struct string_hash_entry *ss_hash;
|
392 |
|
|
struct string_hash_entry *ss_hash_end;
|
393 |
|
|
struct shuffle *fdr;
|
394 |
|
|
struct shuffle *fdr_end;
|
395 |
|
|
struct shuffle *rfd;
|
396 |
|
|
struct shuffle *rfd_end;
|
397 |
|
|
/* The size of the largest file shuffle. */
|
398 |
|
|
unsigned long largest_file_shuffle;
|
399 |
|
|
/* An objalloc for debugging information. */
|
400 |
|
|
struct objalloc *memory;
|
401 |
|
|
};
|
402 |
|
|
|
403 |
|
|
/* Add a file entry to a shuffle list. */
|
404 |
|
|
|
405 |
|
|
static bfd_boolean add_file_shuffle
|
406 |
|
|
PARAMS ((struct accumulate *, struct shuffle **, struct shuffle **,
|
407 |
|
|
bfd *, file_ptr, unsigned long));
|
408 |
|
|
|
409 |
|
|
static bfd_boolean
|
410 |
|
|
add_file_shuffle (ainfo, head, tail, input_bfd, offset, size)
|
411 |
|
|
struct accumulate *ainfo;
|
412 |
|
|
struct shuffle **head;
|
413 |
|
|
struct shuffle **tail;
|
414 |
|
|
bfd *input_bfd;
|
415 |
|
|
file_ptr offset;
|
416 |
|
|
unsigned long size;
|
417 |
|
|
{
|
418 |
|
|
struct shuffle *n;
|
419 |
|
|
|
420 |
|
|
if (*tail != (struct shuffle *) NULL
|
421 |
|
|
&& (*tail)->filep
|
422 |
|
|
&& (*tail)->u.file.input_bfd == input_bfd
|
423 |
|
|
&& (*tail)->u.file.offset + (*tail)->size == (unsigned long) offset)
|
424 |
|
|
{
|
425 |
|
|
/* Just merge this entry onto the existing one. */
|
426 |
|
|
(*tail)->size += size;
|
427 |
|
|
if ((*tail)->size > ainfo->largest_file_shuffle)
|
428 |
|
|
ainfo->largest_file_shuffle = (*tail)->size;
|
429 |
|
|
return TRUE;
|
430 |
|
|
}
|
431 |
|
|
|
432 |
|
|
n = (struct shuffle *) objalloc_alloc (ainfo->memory,
|
433 |
|
|
sizeof (struct shuffle));
|
434 |
|
|
if (!n)
|
435 |
|
|
{
|
436 |
|
|
bfd_set_error (bfd_error_no_memory);
|
437 |
|
|
return FALSE;
|
438 |
|
|
}
|
439 |
|
|
n->next = NULL;
|
440 |
|
|
n->size = size;
|
441 |
|
|
n->filep = TRUE;
|
442 |
|
|
n->u.file.input_bfd = input_bfd;
|
443 |
|
|
n->u.file.offset = offset;
|
444 |
|
|
if (*head == (struct shuffle *) NULL)
|
445 |
|
|
*head = n;
|
446 |
|
|
if (*tail != (struct shuffle *) NULL)
|
447 |
|
|
(*tail)->next = n;
|
448 |
|
|
*tail = n;
|
449 |
|
|
if (size > ainfo->largest_file_shuffle)
|
450 |
|
|
ainfo->largest_file_shuffle = size;
|
451 |
|
|
return TRUE;
|
452 |
|
|
}
|
453 |
|
|
|
454 |
|
|
/* Add a memory entry to a shuffle list. */
|
455 |
|
|
|
456 |
|
|
static bfd_boolean add_memory_shuffle
|
457 |
|
|
PARAMS ((struct accumulate *, struct shuffle **head, struct shuffle **tail,
|
458 |
|
|
bfd_byte *data, unsigned long size));
|
459 |
|
|
|
460 |
|
|
static bfd_boolean
|
461 |
|
|
add_memory_shuffle (ainfo, head, tail, data, size)
|
462 |
|
|
struct accumulate *ainfo;
|
463 |
|
|
struct shuffle **head;
|
464 |
|
|
struct shuffle **tail;
|
465 |
|
|
bfd_byte *data;
|
466 |
|
|
unsigned long size;
|
467 |
|
|
{
|
468 |
|
|
struct shuffle *n;
|
469 |
|
|
|
470 |
|
|
n = (struct shuffle *) objalloc_alloc (ainfo->memory,
|
471 |
|
|
sizeof (struct shuffle));
|
472 |
|
|
if (!n)
|
473 |
|
|
{
|
474 |
|
|
bfd_set_error (bfd_error_no_memory);
|
475 |
|
|
return FALSE;
|
476 |
|
|
}
|
477 |
|
|
n->next = NULL;
|
478 |
|
|
n->size = size;
|
479 |
|
|
n->filep = FALSE;
|
480 |
|
|
n->u.memory = (PTR) data;
|
481 |
|
|
if (*head == (struct shuffle *) NULL)
|
482 |
|
|
*head = n;
|
483 |
|
|
if (*tail != (struct shuffle *) NULL)
|
484 |
|
|
(*tail)->next = n;
|
485 |
|
|
*tail = n;
|
486 |
|
|
return TRUE;
|
487 |
|
|
}
|
488 |
|
|
|
489 |
|
|
/* Initialize the FDR hash table. This returns a handle which is then
|
490 |
|
|
passed in to bfd_ecoff_debug_accumulate, et. al. */
|
491 |
|
|
|
492 |
|
|
PTR
|
493 |
|
|
bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info)
|
494 |
|
|
bfd *output_bfd ATTRIBUTE_UNUSED;
|
495 |
|
|
struct ecoff_debug_info *output_debug;
|
496 |
|
|
const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED;
|
497 |
|
|
struct bfd_link_info *info;
|
498 |
|
|
{
|
499 |
|
|
struct accumulate *ainfo;
|
500 |
|
|
bfd_size_type amt = sizeof (struct accumulate);
|
501 |
|
|
|
502 |
|
|
ainfo = (struct accumulate *) bfd_malloc (amt);
|
503 |
|
|
if (!ainfo)
|
504 |
|
|
return NULL;
|
505 |
|
|
if (!bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc,
|
506 |
|
|
sizeof (struct string_hash_entry), 1021))
|
507 |
|
|
return NULL;
|
508 |
|
|
|
509 |
|
|
ainfo->line = NULL;
|
510 |
|
|
ainfo->line_end = NULL;
|
511 |
|
|
ainfo->pdr = NULL;
|
512 |
|
|
ainfo->pdr_end = NULL;
|
513 |
|
|
ainfo->sym = NULL;
|
514 |
|
|
ainfo->sym_end = NULL;
|
515 |
|
|
ainfo->opt = NULL;
|
516 |
|
|
ainfo->opt_end = NULL;
|
517 |
|
|
ainfo->aux = NULL;
|
518 |
|
|
ainfo->aux_end = NULL;
|
519 |
|
|
ainfo->ss = NULL;
|
520 |
|
|
ainfo->ss_end = NULL;
|
521 |
|
|
ainfo->ss_hash = NULL;
|
522 |
|
|
ainfo->ss_hash_end = NULL;
|
523 |
|
|
ainfo->fdr = NULL;
|
524 |
|
|
ainfo->fdr_end = NULL;
|
525 |
|
|
ainfo->rfd = NULL;
|
526 |
|
|
ainfo->rfd_end = NULL;
|
527 |
|
|
|
528 |
|
|
ainfo->largest_file_shuffle = 0;
|
529 |
|
|
|
530 |
|
|
if (! info->relocatable)
|
531 |
|
|
{
|
532 |
|
|
if (!bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc,
|
533 |
|
|
sizeof (struct string_hash_entry)))
|
534 |
|
|
return NULL;
|
535 |
|
|
|
536 |
|
|
/* The first entry in the string table is the empty string. */
|
537 |
|
|
output_debug->symbolic_header.issMax = 1;
|
538 |
|
|
}
|
539 |
|
|
|
540 |
|
|
ainfo->memory = objalloc_create ();
|
541 |
|
|
if (ainfo->memory == NULL)
|
542 |
|
|
{
|
543 |
|
|
bfd_set_error (bfd_error_no_memory);
|
544 |
|
|
return NULL;
|
545 |
|
|
}
|
546 |
|
|
|
547 |
|
|
return (PTR) ainfo;
|
548 |
|
|
}
|
549 |
|
|
|
550 |
|
|
/* Free the accumulated debugging information. */
|
551 |
|
|
|
552 |
|
|
void
|
553 |
|
|
bfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info)
|
554 |
|
|
PTR handle;
|
555 |
|
|
bfd *output_bfd ATTRIBUTE_UNUSED;
|
556 |
|
|
struct ecoff_debug_info *output_debug ATTRIBUTE_UNUSED;
|
557 |
|
|
const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED;
|
558 |
|
|
struct bfd_link_info *info;
|
559 |
|
|
{
|
560 |
|
|
struct accumulate *ainfo = (struct accumulate *) handle;
|
561 |
|
|
|
562 |
|
|
bfd_hash_table_free (&ainfo->fdr_hash.table);
|
563 |
|
|
|
564 |
|
|
if (! info->relocatable)
|
565 |
|
|
bfd_hash_table_free (&ainfo->str_hash.table);
|
566 |
|
|
|
567 |
|
|
objalloc_free (ainfo->memory);
|
568 |
|
|
|
569 |
|
|
free (ainfo);
|
570 |
|
|
}
|
571 |
|
|
|
572 |
|
|
/* Accumulate the debugging information from INPUT_BFD into
|
573 |
|
|
OUTPUT_BFD. The INPUT_DEBUG argument points to some ECOFF
|
574 |
|
|
debugging information which we want to link into the information
|
575 |
|
|
pointed to by the OUTPUT_DEBUG argument. OUTPUT_SWAP and
|
576 |
|
|
INPUT_SWAP point to the swapping information needed. INFO is the
|
577 |
|
|
linker information structure. HANDLE is returned by
|
578 |
|
|
bfd_ecoff_debug_init. */
|
579 |
|
|
|
580 |
|
|
bfd_boolean
|
581 |
|
|
bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
|
582 |
|
|
input_bfd, input_debug, input_swap,
|
583 |
|
|
info)
|
584 |
|
|
PTR handle;
|
585 |
|
|
bfd *output_bfd;
|
586 |
|
|
struct ecoff_debug_info *output_debug;
|
587 |
|
|
const struct ecoff_debug_swap *output_swap;
|
588 |
|
|
bfd *input_bfd;
|
589 |
|
|
struct ecoff_debug_info *input_debug;
|
590 |
|
|
const struct ecoff_debug_swap *input_swap;
|
591 |
|
|
struct bfd_link_info *info;
|
592 |
|
|
{
|
593 |
|
|
struct accumulate *ainfo = (struct accumulate *) handle;
|
594 |
|
|
void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
|
595 |
|
|
= input_swap->swap_sym_in;
|
596 |
|
|
void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *))
|
597 |
|
|
= input_swap->swap_rfd_in;
|
598 |
|
|
void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
|
599 |
|
|
= output_swap->swap_sym_out;
|
600 |
|
|
void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR))
|
601 |
|
|
= output_swap->swap_fdr_out;
|
602 |
|
|
void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR))
|
603 |
|
|
= output_swap->swap_rfd_out;
|
604 |
|
|
bfd_size_type external_pdr_size = output_swap->external_pdr_size;
|
605 |
|
|
bfd_size_type external_sym_size = output_swap->external_sym_size;
|
606 |
|
|
bfd_size_type external_opt_size = output_swap->external_opt_size;
|
607 |
|
|
bfd_size_type external_fdr_size = output_swap->external_fdr_size;
|
608 |
|
|
bfd_size_type external_rfd_size = output_swap->external_rfd_size;
|
609 |
|
|
HDRR * const output_symhdr = &output_debug->symbolic_header;
|
610 |
|
|
HDRR * const input_symhdr = &input_debug->symbolic_header;
|
611 |
|
|
bfd_vma section_adjust[scMax];
|
612 |
|
|
asection *sec;
|
613 |
|
|
bfd_byte *fdr_start;
|
614 |
|
|
bfd_byte *fdr_ptr;
|
615 |
|
|
bfd_byte *fdr_end;
|
616 |
|
|
bfd_size_type fdr_add;
|
617 |
|
|
unsigned int copied;
|
618 |
|
|
RFDT i;
|
619 |
|
|
unsigned long sz;
|
620 |
|
|
bfd_byte *rfd_out;
|
621 |
|
|
bfd_byte *rfd_in;
|
622 |
|
|
bfd_byte *rfd_end;
|
623 |
|
|
long newrfdbase = 0;
|
624 |
|
|
long oldrfdbase = 0;
|
625 |
|
|
bfd_byte *fdr_out;
|
626 |
|
|
bfd_size_type amt;
|
627 |
|
|
|
628 |
|
|
/* Use section_adjust to hold the value to add to a symbol in a
|
629 |
|
|
particular section. */
|
630 |
|
|
memset ((PTR) section_adjust, 0, sizeof section_adjust);
|
631 |
|
|
|
632 |
|
|
#define SET(name, indx) \
|
633 |
|
|
sec = bfd_get_section_by_name (input_bfd, name); \
|
634 |
|
|
if (sec != NULL) \
|
635 |
|
|
section_adjust[indx] = (sec->output_section->vma \
|
636 |
|
|
+ sec->output_offset \
|
637 |
|
|
- sec->vma);
|
638 |
|
|
|
639 |
|
|
SET (".text", scText);
|
640 |
|
|
SET (".data", scData);
|
641 |
|
|
SET (".bss", scBss);
|
642 |
|
|
SET (".sdata", scSData);
|
643 |
|
|
SET (".sbss", scSBss);
|
644 |
|
|
/* scRdata section may be either .rdata or .rodata. */
|
645 |
|
|
SET (".rdata", scRData);
|
646 |
|
|
SET (".rodata", scRData);
|
647 |
|
|
SET (".init", scInit);
|
648 |
|
|
SET (".fini", scFini);
|
649 |
|
|
SET (".rconst", scRConst);
|
650 |
|
|
|
651 |
|
|
#undef SET
|
652 |
|
|
|
653 |
|
|
/* Find all the debugging information based on the FDR's. We need
|
654 |
|
|
to handle them whether they are swapped or not. */
|
655 |
|
|
if (input_debug->fdr != (FDR *) NULL)
|
656 |
|
|
{
|
657 |
|
|
fdr_start = (bfd_byte *) input_debug->fdr;
|
658 |
|
|
fdr_add = sizeof (FDR);
|
659 |
|
|
}
|
660 |
|
|
else
|
661 |
|
|
{
|
662 |
|
|
fdr_start = (bfd_byte *) input_debug->external_fdr;
|
663 |
|
|
fdr_add = input_swap->external_fdr_size;
|
664 |
|
|
}
|
665 |
|
|
fdr_end = fdr_start + input_symhdr->ifdMax * fdr_add;
|
666 |
|
|
|
667 |
|
|
amt = input_symhdr->ifdMax;
|
668 |
|
|
amt *= sizeof (RFDT);
|
669 |
|
|
input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd, amt);
|
670 |
|
|
|
671 |
|
|
sz = (input_symhdr->crfd + input_symhdr->ifdMax) * external_rfd_size;
|
672 |
|
|
rfd_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
|
673 |
|
|
if (!input_debug->ifdmap || !rfd_out)
|
674 |
|
|
{
|
675 |
|
|
bfd_set_error (bfd_error_no_memory);
|
676 |
|
|
return FALSE;
|
677 |
|
|
}
|
678 |
|
|
if (!add_memory_shuffle (ainfo, &ainfo->rfd, &ainfo->rfd_end, rfd_out, sz))
|
679 |
|
|
return FALSE;
|
680 |
|
|
|
681 |
|
|
copied = 0;
|
682 |
|
|
|
683 |
|
|
/* Look through the FDR's to see which ones we are going to include
|
684 |
|
|
in the final output. We do not want duplicate FDR information
|
685 |
|
|
for header files, because ECOFF debugging is often very large.
|
686 |
|
|
When we find an FDR with no line information which can be merged,
|
687 |
|
|
we look it up in a hash table to ensure that we only include it
|
688 |
|
|
once. We keep a table mapping FDR numbers to the final number
|
689 |
|
|
they get with the BFD, so that we can refer to it when we write
|
690 |
|
|
out the external symbols. */
|
691 |
|
|
for (fdr_ptr = fdr_start, i = 0;
|
692 |
|
|
fdr_ptr < fdr_end;
|
693 |
|
|
fdr_ptr += fdr_add, i++, rfd_out += external_rfd_size)
|
694 |
|
|
{
|
695 |
|
|
FDR fdr;
|
696 |
|
|
|
697 |
|
|
if (input_debug->fdr != (FDR *) NULL)
|
698 |
|
|
fdr = *(FDR *) fdr_ptr;
|
699 |
|
|
else
|
700 |
|
|
(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
|
701 |
|
|
|
702 |
|
|
/* See if this FDR can be merged with an existing one. */
|
703 |
|
|
if (fdr.cbLine == 0 && fdr.rss != -1 && fdr.fMerge)
|
704 |
|
|
{
|
705 |
|
|
const char *name;
|
706 |
|
|
char *lookup;
|
707 |
|
|
struct string_hash_entry *fh;
|
708 |
|
|
|
709 |
|
|
/* We look up a string formed from the file name and the
|
710 |
|
|
number of symbols and aux entries. Sometimes an include
|
711 |
|
|
file will conditionally define a typedef or something
|
712 |
|
|
based on the order of include files. Using the number of
|
713 |
|
|
symbols and aux entries as a hash reduces the chance that
|
714 |
|
|
we will merge symbol information that should not be
|
715 |
|
|
merged. */
|
716 |
|
|
name = input_debug->ss + fdr.issBase + fdr.rss;
|
717 |
|
|
|
718 |
|
|
lookup = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 20);
|
719 |
|
|
if (lookup == NULL)
|
720 |
|
|
return FALSE;
|
721 |
225 |
jeremybenn |
sprintf (lookup, "%s %lx %lx", name, (unsigned long) fdr.csym,
|
722 |
|
|
(unsigned long) fdr.caux);
|
723 |
24 |
jeremybenn |
|
724 |
|
|
fh = string_hash_lookup (&ainfo->fdr_hash, lookup, TRUE, TRUE);
|
725 |
|
|
free (lookup);
|
726 |
|
|
if (fh == (struct string_hash_entry *) NULL)
|
727 |
|
|
return FALSE;
|
728 |
|
|
|
729 |
|
|
if (fh->val != -1)
|
730 |
|
|
{
|
731 |
|
|
input_debug->ifdmap[i] = fh->val;
|
732 |
|
|
(*swap_rfd_out) (output_bfd, input_debug->ifdmap + i,
|
733 |
|
|
(PTR) rfd_out);
|
734 |
|
|
|
735 |
|
|
/* Don't copy this FDR. */
|
736 |
|
|
continue;
|
737 |
|
|
}
|
738 |
|
|
|
739 |
|
|
fh->val = output_symhdr->ifdMax + copied;
|
740 |
|
|
}
|
741 |
|
|
|
742 |
|
|
input_debug->ifdmap[i] = output_symhdr->ifdMax + copied;
|
743 |
|
|
(*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, (PTR) rfd_out);
|
744 |
|
|
++copied;
|
745 |
|
|
}
|
746 |
|
|
|
747 |
|
|
newrfdbase = output_symhdr->crfd;
|
748 |
|
|
output_symhdr->crfd += input_symhdr->ifdMax;
|
749 |
|
|
|
750 |
|
|
/* Copy over any existing RFD's. RFD's are only created by the
|
751 |
|
|
linker, so this will only happen for input files which are the
|
752 |
|
|
result of a partial link. */
|
753 |
|
|
rfd_in = (bfd_byte *) input_debug->external_rfd;
|
754 |
|
|
rfd_end = rfd_in + input_symhdr->crfd * input_swap->external_rfd_size;
|
755 |
|
|
for (;
|
756 |
|
|
rfd_in < rfd_end;
|
757 |
|
|
rfd_in += input_swap->external_rfd_size)
|
758 |
|
|
{
|
759 |
|
|
RFDT rfd;
|
760 |
|
|
|
761 |
|
|
(*swap_rfd_in) (input_bfd, (PTR) rfd_in, &rfd);
|
762 |
|
|
BFD_ASSERT (rfd >= 0 && rfd < input_symhdr->ifdMax);
|
763 |
|
|
rfd = input_debug->ifdmap[rfd];
|
764 |
|
|
(*swap_rfd_out) (output_bfd, &rfd, (PTR) rfd_out);
|
765 |
|
|
rfd_out += external_rfd_size;
|
766 |
|
|
}
|
767 |
|
|
|
768 |
|
|
oldrfdbase = output_symhdr->crfd;
|
769 |
|
|
output_symhdr->crfd += input_symhdr->crfd;
|
770 |
|
|
|
771 |
|
|
/* Look through the FDR's and copy over all associated debugging
|
772 |
|
|
information. */
|
773 |
|
|
sz = copied * external_fdr_size;
|
774 |
|
|
fdr_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
|
775 |
|
|
if (!fdr_out)
|
776 |
|
|
{
|
777 |
|
|
bfd_set_error (bfd_error_no_memory);
|
778 |
|
|
return FALSE;
|
779 |
|
|
}
|
780 |
|
|
if (!add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, fdr_out, sz))
|
781 |
|
|
return FALSE;
|
782 |
|
|
for (fdr_ptr = fdr_start, i = 0;
|
783 |
|
|
fdr_ptr < fdr_end;
|
784 |
|
|
fdr_ptr += fdr_add, i++)
|
785 |
|
|
{
|
786 |
|
|
FDR fdr;
|
787 |
|
|
bfd_byte *sym_out;
|
788 |
|
|
bfd_byte *lraw_src;
|
789 |
|
|
bfd_byte *lraw_end;
|
790 |
|
|
bfd_boolean fgotfilename;
|
791 |
|
|
|
792 |
|
|
if (input_debug->ifdmap[i] < output_symhdr->ifdMax)
|
793 |
|
|
{
|
794 |
|
|
/* We are not copying this FDR. */
|
795 |
|
|
continue;
|
796 |
|
|
}
|
797 |
|
|
|
798 |
|
|
if (input_debug->fdr != (FDR *) NULL)
|
799 |
|
|
fdr = *(FDR *) fdr_ptr;
|
800 |
|
|
else
|
801 |
|
|
(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
|
802 |
|
|
|
803 |
|
|
/* FIXME: It is conceivable that this FDR points to the .init or
|
804 |
|
|
.fini section, in which case this will not do the right
|
805 |
|
|
thing. */
|
806 |
|
|
fdr.adr += section_adjust[scText];
|
807 |
|
|
|
808 |
|
|
/* Swap in the local symbols, adjust their values, and swap them
|
809 |
|
|
out again. */
|
810 |
|
|
fgotfilename = FALSE;
|
811 |
|
|
sz = fdr.csym * external_sym_size;
|
812 |
|
|
sym_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
|
813 |
|
|
if (!sym_out)
|
814 |
|
|
{
|
815 |
|
|
bfd_set_error (bfd_error_no_memory);
|
816 |
|
|
return FALSE;
|
817 |
|
|
}
|
818 |
|
|
if (!add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out,
|
819 |
|
|
sz))
|
820 |
|
|
return FALSE;
|
821 |
|
|
lraw_src = ((bfd_byte *) input_debug->external_sym
|
822 |
|
|
+ fdr.isymBase * input_swap->external_sym_size);
|
823 |
|
|
lraw_end = lraw_src + fdr.csym * input_swap->external_sym_size;
|
824 |
|
|
for (; lraw_src < lraw_end; lraw_src += input_swap->external_sym_size)
|
825 |
|
|
{
|
826 |
|
|
SYMR internal_sym;
|
827 |
|
|
|
828 |
|
|
(*swap_sym_in) (input_bfd, (PTR) lraw_src, &internal_sym);
|
829 |
|
|
|
830 |
|
|
BFD_ASSERT (internal_sym.sc != scCommon
|
831 |
|
|
&& internal_sym.sc != scSCommon);
|
832 |
|
|
|
833 |
|
|
/* Adjust the symbol value if appropriate. */
|
834 |
|
|
switch (internal_sym.st)
|
835 |
|
|
{
|
836 |
|
|
case stNil:
|
837 |
|
|
if (ECOFF_IS_STAB (&internal_sym))
|
838 |
|
|
break;
|
839 |
|
|
/* Fall through. */
|
840 |
|
|
case stGlobal:
|
841 |
|
|
case stStatic:
|
842 |
|
|
case stLabel:
|
843 |
|
|
case stProc:
|
844 |
|
|
case stStaticProc:
|
845 |
|
|
internal_sym.value += section_adjust[internal_sym.sc];
|
846 |
|
|
break;
|
847 |
|
|
|
848 |
|
|
default:
|
849 |
|
|
break;
|
850 |
|
|
}
|
851 |
|
|
|
852 |
|
|
/* If we are doing a final link, we hash all the strings in
|
853 |
|
|
the local symbol table together. This reduces the amount
|
854 |
|
|
of space required by debugging information. We don't do
|
855 |
|
|
this when performing a relocatable link because it would
|
856 |
|
|
prevent us from easily merging different FDR's. */
|
857 |
|
|
if (! info->relocatable)
|
858 |
|
|
{
|
859 |
|
|
bfd_boolean ffilename;
|
860 |
|
|
const char *name;
|
861 |
|
|
|
862 |
|
|
if (! fgotfilename && internal_sym.iss == fdr.rss)
|
863 |
|
|
ffilename = TRUE;
|
864 |
|
|
else
|
865 |
|
|
ffilename = FALSE;
|
866 |
|
|
|
867 |
|
|
/* Hash the name into the string table. */
|
868 |
|
|
name = input_debug->ss + fdr.issBase + internal_sym.iss;
|
869 |
|
|
if (*name == '\0')
|
870 |
|
|
internal_sym.iss = 0;
|
871 |
|
|
else
|
872 |
|
|
{
|
873 |
|
|
struct string_hash_entry *sh;
|
874 |
|
|
|
875 |
|
|
sh = string_hash_lookup (&ainfo->str_hash, name, TRUE, TRUE);
|
876 |
|
|
if (sh == (struct string_hash_entry *) NULL)
|
877 |
|
|
return FALSE;
|
878 |
|
|
if (sh->val == -1)
|
879 |
|
|
{
|
880 |
|
|
sh->val = output_symhdr->issMax;
|
881 |
|
|
output_symhdr->issMax += strlen (name) + 1;
|
882 |
|
|
if (ainfo->ss_hash == (struct string_hash_entry *) NULL)
|
883 |
|
|
ainfo->ss_hash = sh;
|
884 |
|
|
if (ainfo->ss_hash_end
|
885 |
|
|
!= (struct string_hash_entry *) NULL)
|
886 |
|
|
ainfo->ss_hash_end->next = sh;
|
887 |
|
|
ainfo->ss_hash_end = sh;
|
888 |
|
|
}
|
889 |
|
|
internal_sym.iss = sh->val;
|
890 |
|
|
}
|
891 |
|
|
|
892 |
|
|
if (ffilename)
|
893 |
|
|
{
|
894 |
|
|
fdr.rss = internal_sym.iss;
|
895 |
|
|
fgotfilename = TRUE;
|
896 |
|
|
}
|
897 |
|
|
}
|
898 |
|
|
|
899 |
|
|
(*swap_sym_out) (output_bfd, &internal_sym, sym_out);
|
900 |
|
|
sym_out += external_sym_size;
|
901 |
|
|
}
|
902 |
|
|
|
903 |
|
|
fdr.isymBase = output_symhdr->isymMax;
|
904 |
|
|
output_symhdr->isymMax += fdr.csym;
|
905 |
|
|
|
906 |
|
|
/* Copy the information that does not need swapping. */
|
907 |
|
|
|
908 |
|
|
/* FIXME: If we are relaxing, we need to adjust the line
|
909 |
|
|
numbers. Frankly, forget it. Anybody using stabs debugging
|
910 |
|
|
information will not use this line number information, and
|
911 |
|
|
stabs are adjusted correctly. */
|
912 |
|
|
if (fdr.cbLine > 0)
|
913 |
|
|
{
|
914 |
|
|
file_ptr pos = input_symhdr->cbLineOffset + fdr.cbLineOffset;
|
915 |
|
|
if (!add_file_shuffle (ainfo, &ainfo->line, &ainfo->line_end,
|
916 |
|
|
input_bfd, pos, (unsigned long) fdr.cbLine))
|
917 |
|
|
return FALSE;
|
918 |
|
|
fdr.ilineBase = output_symhdr->ilineMax;
|
919 |
|
|
fdr.cbLineOffset = output_symhdr->cbLine;
|
920 |
|
|
output_symhdr->ilineMax += fdr.cline;
|
921 |
|
|
output_symhdr->cbLine += fdr.cbLine;
|
922 |
|
|
}
|
923 |
|
|
if (fdr.caux > 0)
|
924 |
|
|
{
|
925 |
|
|
file_ptr pos = (input_symhdr->cbAuxOffset
|
926 |
|
|
+ fdr.iauxBase * sizeof (union aux_ext));
|
927 |
|
|
if (!add_file_shuffle (ainfo, &ainfo->aux, &ainfo->aux_end,
|
928 |
|
|
input_bfd, pos,
|
929 |
|
|
fdr.caux * sizeof (union aux_ext)))
|
930 |
|
|
return FALSE;
|
931 |
|
|
fdr.iauxBase = output_symhdr->iauxMax;
|
932 |
|
|
output_symhdr->iauxMax += fdr.caux;
|
933 |
|
|
}
|
934 |
|
|
if (! info->relocatable)
|
935 |
|
|
{
|
936 |
|
|
|
937 |
|
|
/* When are are hashing strings, we lie about the number of
|
938 |
|
|
strings attached to each FDR. We need to set cbSs
|
939 |
|
|
because some versions of dbx apparently use it to decide
|
940 |
|
|
how much of the string table to read in. */
|
941 |
|
|
fdr.issBase = 0;
|
942 |
|
|
fdr.cbSs = output_symhdr->issMax;
|
943 |
|
|
}
|
944 |
|
|
else if (fdr.cbSs > 0)
|
945 |
|
|
{
|
946 |
|
|
file_ptr pos = input_symhdr->cbSsOffset + fdr.issBase;
|
947 |
|
|
if (!add_file_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end,
|
948 |
|
|
input_bfd, pos, (unsigned long) fdr.cbSs))
|
949 |
|
|
return FALSE;
|
950 |
|
|
fdr.issBase = output_symhdr->issMax;
|
951 |
|
|
output_symhdr->issMax += fdr.cbSs;
|
952 |
|
|
}
|
953 |
|
|
|
954 |
|
|
if (output_bfd->xvec->header_byteorder
|
955 |
|
|
== input_bfd->xvec->header_byteorder)
|
956 |
|
|
{
|
957 |
|
|
/* The two BFD's have the same endianness, and we don't have
|
958 |
|
|
to adjust the PDR addresses, so simply copying the
|
959 |
|
|
information will suffice. */
|
960 |
|
|
BFD_ASSERT (external_pdr_size == input_swap->external_pdr_size);
|
961 |
|
|
if (fdr.cpd > 0)
|
962 |
|
|
{
|
963 |
|
|
file_ptr pos = (input_symhdr->cbPdOffset
|
964 |
|
|
+ fdr.ipdFirst * external_pdr_size);
|
965 |
|
|
unsigned long size = fdr.cpd * external_pdr_size;
|
966 |
|
|
if (!add_file_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end,
|
967 |
|
|
input_bfd, pos, size))
|
968 |
|
|
return FALSE;
|
969 |
|
|
}
|
970 |
|
|
BFD_ASSERT (external_opt_size == input_swap->external_opt_size);
|
971 |
|
|
if (fdr.copt > 0)
|
972 |
|
|
{
|
973 |
|
|
file_ptr pos = (input_symhdr->cbOptOffset
|
974 |
|
|
+ fdr.ioptBase * external_opt_size);
|
975 |
|
|
unsigned long size = fdr.copt * external_opt_size;
|
976 |
|
|
if (!add_file_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end,
|
977 |
|
|
input_bfd, pos, size))
|
978 |
|
|
return FALSE;
|
979 |
|
|
}
|
980 |
|
|
}
|
981 |
|
|
else
|
982 |
|
|
{
|
983 |
|
|
bfd_size_type outsz, insz;
|
984 |
|
|
bfd_byte *in;
|
985 |
|
|
bfd_byte *end;
|
986 |
|
|
bfd_byte *out;
|
987 |
|
|
|
988 |
|
|
/* The two BFD's have different endianness, so we must swap
|
989 |
|
|
everything in and out. This code would always work, but
|
990 |
|
|
it would be unnecessarily slow in the normal case. */
|
991 |
|
|
outsz = external_pdr_size;
|
992 |
|
|
insz = input_swap->external_pdr_size;
|
993 |
|
|
in = ((bfd_byte *) input_debug->external_pdr
|
994 |
|
|
+ fdr.ipdFirst * insz);
|
995 |
|
|
end = in + fdr.cpd * insz;
|
996 |
|
|
sz = fdr.cpd * outsz;
|
997 |
|
|
out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
|
998 |
|
|
if (!out)
|
999 |
|
|
{
|
1000 |
|
|
bfd_set_error (bfd_error_no_memory);
|
1001 |
|
|
return FALSE;
|
1002 |
|
|
}
|
1003 |
|
|
if (!add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out,
|
1004 |
|
|
sz))
|
1005 |
|
|
return FALSE;
|
1006 |
|
|
for (; in < end; in += insz, out += outsz)
|
1007 |
|
|
{
|
1008 |
|
|
PDR pdr;
|
1009 |
|
|
|
1010 |
|
|
(*input_swap->swap_pdr_in) (input_bfd, (PTR) in, &pdr);
|
1011 |
|
|
(*output_swap->swap_pdr_out) (output_bfd, &pdr, (PTR) out);
|
1012 |
|
|
}
|
1013 |
|
|
|
1014 |
|
|
/* Swap over the optimization information. */
|
1015 |
|
|
outsz = external_opt_size;
|
1016 |
|
|
insz = input_swap->external_opt_size;
|
1017 |
|
|
in = ((bfd_byte *) input_debug->external_opt
|
1018 |
|
|
+ fdr.ioptBase * insz);
|
1019 |
|
|
end = in + fdr.copt * insz;
|
1020 |
|
|
sz = fdr.copt * outsz;
|
1021 |
|
|
out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
|
1022 |
|
|
if (!out)
|
1023 |
|
|
{
|
1024 |
|
|
bfd_set_error (bfd_error_no_memory);
|
1025 |
|
|
return FALSE;
|
1026 |
|
|
}
|
1027 |
|
|
if (!add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out,
|
1028 |
|
|
sz))
|
1029 |
|
|
return FALSE;
|
1030 |
|
|
for (; in < end; in += insz, out += outsz)
|
1031 |
|
|
{
|
1032 |
|
|
OPTR opt;
|
1033 |
|
|
|
1034 |
|
|
(*input_swap->swap_opt_in) (input_bfd, (PTR) in, &opt);
|
1035 |
|
|
(*output_swap->swap_opt_out) (output_bfd, &opt, (PTR) out);
|
1036 |
|
|
}
|
1037 |
|
|
}
|
1038 |
|
|
|
1039 |
|
|
fdr.ipdFirst = output_symhdr->ipdMax;
|
1040 |
|
|
output_symhdr->ipdMax += fdr.cpd;
|
1041 |
|
|
fdr.ioptBase = output_symhdr->ioptMax;
|
1042 |
|
|
output_symhdr->ioptMax += fdr.copt;
|
1043 |
|
|
|
1044 |
|
|
if (fdr.crfd <= 0)
|
1045 |
|
|
{
|
1046 |
|
|
/* Point this FDR at the table of RFD's we created. */
|
1047 |
|
|
fdr.rfdBase = newrfdbase;
|
1048 |
|
|
fdr.crfd = input_symhdr->ifdMax;
|
1049 |
|
|
}
|
1050 |
|
|
else
|
1051 |
|
|
{
|
1052 |
|
|
/* Point this FDR at the remapped RFD's. */
|
1053 |
|
|
fdr.rfdBase += oldrfdbase;
|
1054 |
|
|
}
|
1055 |
|
|
|
1056 |
|
|
(*swap_fdr_out) (output_bfd, &fdr, fdr_out);
|
1057 |
|
|
fdr_out += external_fdr_size;
|
1058 |
|
|
++output_symhdr->ifdMax;
|
1059 |
|
|
}
|
1060 |
|
|
|
1061 |
|
|
return TRUE;
|
1062 |
|
|
}
|
1063 |
|
|
|
1064 |
|
|
/* Add a string to the debugging information we are accumulating.
|
1065 |
|
|
Return the offset from the fdr string base. */
|
1066 |
|
|
|
1067 |
|
|
static long ecoff_add_string
|
1068 |
|
|
PARAMS ((struct accumulate *, struct bfd_link_info *,
|
1069 |
|
|
struct ecoff_debug_info *, FDR *fdr, const char *string));
|
1070 |
|
|
|
1071 |
|
|
static long
|
1072 |
|
|
ecoff_add_string (ainfo, info, debug, fdr, string)
|
1073 |
|
|
struct accumulate *ainfo;
|
1074 |
|
|
struct bfd_link_info *info;
|
1075 |
|
|
struct ecoff_debug_info *debug;
|
1076 |
|
|
FDR *fdr;
|
1077 |
|
|
const char *string;
|
1078 |
|
|
{
|
1079 |
|
|
HDRR *symhdr;
|
1080 |
|
|
size_t len;
|
1081 |
|
|
bfd_size_type ret;
|
1082 |
|
|
|
1083 |
|
|
symhdr = &debug->symbolic_header;
|
1084 |
|
|
len = strlen (string);
|
1085 |
|
|
if (info->relocatable)
|
1086 |
|
|
{
|
1087 |
|
|
if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, (PTR) string,
|
1088 |
|
|
len + 1))
|
1089 |
|
|
return -1;
|
1090 |
|
|
ret = symhdr->issMax;
|
1091 |
|
|
symhdr->issMax += len + 1;
|
1092 |
|
|
fdr->cbSs += len + 1;
|
1093 |
|
|
}
|
1094 |
|
|
else
|
1095 |
|
|
{
|
1096 |
|
|
struct string_hash_entry *sh;
|
1097 |
|
|
|
1098 |
|
|
sh = string_hash_lookup (&ainfo->str_hash, string, TRUE, TRUE);
|
1099 |
|
|
if (sh == (struct string_hash_entry *) NULL)
|
1100 |
|
|
return -1;
|
1101 |
|
|
if (sh->val == -1)
|
1102 |
|
|
{
|
1103 |
|
|
sh->val = symhdr->issMax;
|
1104 |
|
|
symhdr->issMax += len + 1;
|
1105 |
|
|
if (ainfo->ss_hash == (struct string_hash_entry *) NULL)
|
1106 |
|
|
ainfo->ss_hash = sh;
|
1107 |
|
|
if (ainfo->ss_hash_end
|
1108 |
|
|
!= (struct string_hash_entry *) NULL)
|
1109 |
|
|
ainfo->ss_hash_end->next = sh;
|
1110 |
|
|
ainfo->ss_hash_end = sh;
|
1111 |
|
|
}
|
1112 |
|
|
ret = sh->val;
|
1113 |
|
|
}
|
1114 |
|
|
|
1115 |
|
|
return ret;
|
1116 |
|
|
}
|
1117 |
|
|
|
1118 |
|
|
/* Add debugging information from a non-ECOFF file. */
|
1119 |
|
|
|
1120 |
|
|
bfd_boolean
|
1121 |
|
|
bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
|
1122 |
|
|
output_swap, input_bfd, info)
|
1123 |
|
|
PTR handle;
|
1124 |
|
|
bfd *output_bfd;
|
1125 |
|
|
struct ecoff_debug_info *output_debug;
|
1126 |
|
|
const struct ecoff_debug_swap *output_swap;
|
1127 |
|
|
bfd *input_bfd;
|
1128 |
|
|
struct bfd_link_info *info;
|
1129 |
|
|
{
|
1130 |
|
|
struct accumulate *ainfo = (struct accumulate *) handle;
|
1131 |
|
|
void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
|
1132 |
|
|
= output_swap->swap_sym_out;
|
1133 |
|
|
HDRR *output_symhdr = &output_debug->symbolic_header;
|
1134 |
|
|
FDR fdr;
|
1135 |
|
|
asection *sec;
|
1136 |
|
|
asymbol **symbols;
|
1137 |
|
|
asymbol **sym_ptr;
|
1138 |
|
|
asymbol **sym_end;
|
1139 |
|
|
long symsize;
|
1140 |
|
|
long symcount;
|
1141 |
|
|
PTR external_fdr;
|
1142 |
|
|
|
1143 |
|
|
memset ((PTR) &fdr, 0, sizeof fdr);
|
1144 |
|
|
|
1145 |
|
|
sec = bfd_get_section_by_name (input_bfd, ".text");
|
1146 |
|
|
if (sec != NULL)
|
1147 |
|
|
fdr.adr = sec->output_section->vma + sec->output_offset;
|
1148 |
|
|
else
|
1149 |
|
|
{
|
1150 |
|
|
/* FIXME: What about .init or .fini? */
|
1151 |
|
|
fdr.adr = 0;
|
1152 |
|
|
}
|
1153 |
|
|
|
1154 |
|
|
fdr.issBase = output_symhdr->issMax;
|
1155 |
|
|
fdr.cbSs = 0;
|
1156 |
|
|
fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr,
|
1157 |
|
|
input_bfd->filename);
|
1158 |
|
|
if (fdr.rss == -1)
|
1159 |
|
|
return FALSE;
|
1160 |
|
|
fdr.isymBase = output_symhdr->isymMax;
|
1161 |
|
|
|
1162 |
|
|
/* Get the local symbols from the input BFD. */
|
1163 |
|
|
symsize = bfd_get_symtab_upper_bound (input_bfd);
|
1164 |
|
|
if (symsize < 0)
|
1165 |
|
|
return FALSE;
|
1166 |
|
|
symbols = (asymbol **) bfd_alloc (output_bfd, (bfd_size_type) symsize);
|
1167 |
|
|
if (symbols == (asymbol **) NULL)
|
1168 |
|
|
return FALSE;
|
1169 |
|
|
symcount = bfd_canonicalize_symtab (input_bfd, symbols);
|
1170 |
|
|
if (symcount < 0)
|
1171 |
|
|
return FALSE;
|
1172 |
|
|
sym_end = symbols + symcount;
|
1173 |
|
|
|
1174 |
|
|
/* Handle the local symbols. Any external symbols are handled
|
1175 |
|
|
separately. */
|
1176 |
|
|
fdr.csym = 0;
|
1177 |
|
|
for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++)
|
1178 |
|
|
{
|
1179 |
|
|
SYMR internal_sym;
|
1180 |
|
|
PTR external_sym;
|
1181 |
|
|
|
1182 |
|
|
if (((*sym_ptr)->flags & BSF_EXPORT) != 0)
|
1183 |
|
|
continue;
|
1184 |
|
|
memset ((PTR) &internal_sym, 0, sizeof internal_sym);
|
1185 |
|
|
internal_sym.iss = ecoff_add_string (ainfo, info, output_debug, &fdr,
|
1186 |
|
|
(*sym_ptr)->name);
|
1187 |
|
|
|
1188 |
|
|
if (internal_sym.iss == -1)
|
1189 |
|
|
return FALSE;
|
1190 |
|
|
if (bfd_is_com_section ((*sym_ptr)->section)
|
1191 |
|
|
|| bfd_is_und_section ((*sym_ptr)->section))
|
1192 |
|
|
internal_sym.value = (*sym_ptr)->value;
|
1193 |
|
|
else
|
1194 |
|
|
internal_sym.value = ((*sym_ptr)->value
|
1195 |
|
|
+ (*sym_ptr)->section->output_offset
|
1196 |
|
|
+ (*sym_ptr)->section->output_section->vma);
|
1197 |
|
|
internal_sym.st = stNil;
|
1198 |
|
|
internal_sym.sc = scUndefined;
|
1199 |
|
|
internal_sym.index = indexNil;
|
1200 |
|
|
|
1201 |
|
|
external_sym = (PTR) objalloc_alloc (ainfo->memory,
|
1202 |
|
|
output_swap->external_sym_size);
|
1203 |
|
|
if (!external_sym)
|
1204 |
|
|
{
|
1205 |
|
|
bfd_set_error (bfd_error_no_memory);
|
1206 |
|
|
return FALSE;
|
1207 |
|
|
}
|
1208 |
|
|
(*swap_sym_out) (output_bfd, &internal_sym, external_sym);
|
1209 |
|
|
add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end,
|
1210 |
|
|
external_sym,
|
1211 |
|
|
(unsigned long) output_swap->external_sym_size);
|
1212 |
|
|
++fdr.csym;
|
1213 |
|
|
++output_symhdr->isymMax;
|
1214 |
|
|
}
|
1215 |
|
|
|
1216 |
|
|
bfd_release (output_bfd, (PTR) symbols);
|
1217 |
|
|
|
1218 |
|
|
/* Leave everything else in the FDR zeroed out. This will cause
|
1219 |
|
|
the lang field to be langC. The fBigendian field will
|
1220 |
|
|
indicate little endian format, but it doesn't matter because
|
1221 |
|
|
it only applies to aux fields and there are none. */
|
1222 |
|
|
external_fdr = (PTR) objalloc_alloc (ainfo->memory,
|
1223 |
|
|
output_swap->external_fdr_size);
|
1224 |
|
|
if (!external_fdr)
|
1225 |
|
|
{
|
1226 |
|
|
bfd_set_error (bfd_error_no_memory);
|
1227 |
|
|
return FALSE;
|
1228 |
|
|
}
|
1229 |
|
|
(*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr);
|
1230 |
|
|
add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end,
|
1231 |
|
|
external_fdr,
|
1232 |
|
|
(unsigned long) output_swap->external_fdr_size);
|
1233 |
|
|
|
1234 |
|
|
++output_symhdr->ifdMax;
|
1235 |
|
|
|
1236 |
|
|
return TRUE;
|
1237 |
|
|
}
|
1238 |
|
|
|
1239 |
|
|
/* Set up ECOFF debugging information for the external symbols.
|
1240 |
|
|
FIXME: This is done using a memory buffer, but it should be
|
1241 |
|
|
probably be changed to use a shuffle structure. The assembler uses
|
1242 |
|
|
this interface, so that must be changed to do something else. */
|
1243 |
|
|
|
1244 |
|
|
bfd_boolean
|
1245 |
|
|
bfd_ecoff_debug_externals (abfd, debug, swap, relocatable, get_extr,
|
1246 |
|
|
set_index)
|
1247 |
|
|
bfd *abfd;
|
1248 |
|
|
struct ecoff_debug_info *debug;
|
1249 |
|
|
const struct ecoff_debug_swap *swap;
|
1250 |
|
|
bfd_boolean relocatable;
|
1251 |
|
|
bfd_boolean (*get_extr) PARAMS ((asymbol *, EXTR *));
|
1252 |
|
|
void (*set_index) PARAMS ((asymbol *, bfd_size_type));
|
1253 |
|
|
{
|
1254 |
|
|
HDRR * const symhdr = &debug->symbolic_header;
|
1255 |
|
|
asymbol **sym_ptr_ptr;
|
1256 |
|
|
size_t c;
|
1257 |
|
|
|
1258 |
|
|
sym_ptr_ptr = bfd_get_outsymbols (abfd);
|
1259 |
|
|
if (sym_ptr_ptr == NULL)
|
1260 |
|
|
return TRUE;
|
1261 |
|
|
|
1262 |
|
|
for (c = bfd_get_symcount (abfd); c > 0; c--, sym_ptr_ptr++)
|
1263 |
|
|
{
|
1264 |
|
|
asymbol *sym_ptr;
|
1265 |
|
|
EXTR esym;
|
1266 |
|
|
|
1267 |
|
|
sym_ptr = *sym_ptr_ptr;
|
1268 |
|
|
|
1269 |
|
|
/* Get the external symbol information. */
|
1270 |
|
|
if (! (*get_extr) (sym_ptr, &esym))
|
1271 |
|
|
continue;
|
1272 |
|
|
|
1273 |
|
|
/* If we're producing an executable, move common symbols into
|
1274 |
|
|
bss. */
|
1275 |
|
|
if (! relocatable)
|
1276 |
|
|
{
|
1277 |
|
|
if (esym.asym.sc == scCommon)
|
1278 |
|
|
esym.asym.sc = scBss;
|
1279 |
|
|
else if (esym.asym.sc == scSCommon)
|
1280 |
|
|
esym.asym.sc = scSBss;
|
1281 |
|
|
}
|
1282 |
|
|
|
1283 |
|
|
if (bfd_is_com_section (sym_ptr->section)
|
1284 |
|
|
|| bfd_is_und_section (sym_ptr->section)
|
1285 |
|
|
|| sym_ptr->section->output_section == (asection *) NULL)
|
1286 |
|
|
{
|
1287 |
|
|
/* FIXME: gas does not keep the value of a small undefined
|
1288 |
|
|
symbol in the symbol itself, because of relocation
|
1289 |
|
|
problems. */
|
1290 |
|
|
if (esym.asym.sc != scSUndefined
|
1291 |
|
|
|| esym.asym.value == 0
|
1292 |
|
|
|| sym_ptr->value != 0)
|
1293 |
|
|
esym.asym.value = sym_ptr->value;
|
1294 |
|
|
}
|
1295 |
|
|
else
|
1296 |
|
|
esym.asym.value = (sym_ptr->value
|
1297 |
|
|
+ sym_ptr->section->output_offset
|
1298 |
|
|
+ sym_ptr->section->output_section->vma);
|
1299 |
|
|
|
1300 |
|
|
if (set_index)
|
1301 |
|
|
(*set_index) (sym_ptr, (bfd_size_type) symhdr->iextMax);
|
1302 |
|
|
|
1303 |
|
|
if (! bfd_ecoff_debug_one_external (abfd, debug, swap,
|
1304 |
|
|
sym_ptr->name, &esym))
|
1305 |
|
|
return FALSE;
|
1306 |
|
|
}
|
1307 |
|
|
|
1308 |
|
|
return TRUE;
|
1309 |
|
|
}
|
1310 |
|
|
|
1311 |
|
|
/* Add a single external symbol to the debugging information. */
|
1312 |
|
|
|
1313 |
|
|
bfd_boolean
|
1314 |
|
|
bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym)
|
1315 |
|
|
bfd *abfd;
|
1316 |
|
|
struct ecoff_debug_info *debug;
|
1317 |
|
|
const struct ecoff_debug_swap *swap;
|
1318 |
|
|
const char *name;
|
1319 |
|
|
EXTR *esym;
|
1320 |
|
|
{
|
1321 |
|
|
const bfd_size_type external_ext_size = swap->external_ext_size;
|
1322 |
|
|
void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR))
|
1323 |
|
|
= swap->swap_ext_out;
|
1324 |
|
|
HDRR * const symhdr = &debug->symbolic_header;
|
1325 |
|
|
size_t namelen;
|
1326 |
|
|
|
1327 |
|
|
namelen = strlen (name);
|
1328 |
|
|
|
1329 |
|
|
if ((size_t) (debug->ssext_end - debug->ssext)
|
1330 |
|
|
< symhdr->issExtMax + namelen + 1)
|
1331 |
|
|
{
|
1332 |
|
|
if (! ecoff_add_bytes ((char **) &debug->ssext,
|
1333 |
|
|
(char **) &debug->ssext_end,
|
1334 |
|
|
symhdr->issExtMax + namelen + 1))
|
1335 |
|
|
return FALSE;
|
1336 |
|
|
}
|
1337 |
|
|
if ((size_t) ((char *) debug->external_ext_end
|
1338 |
|
|
- (char *) debug->external_ext)
|
1339 |
|
|
< (symhdr->iextMax + 1) * external_ext_size)
|
1340 |
|
|
{
|
1341 |
|
|
char *external_ext = debug->external_ext;
|
1342 |
|
|
char *external_ext_end = debug->external_ext_end;
|
1343 |
|
|
if (! ecoff_add_bytes ((char **) &external_ext,
|
1344 |
|
|
(char **) &external_ext_end,
|
1345 |
|
|
(symhdr->iextMax + 1) * (size_t) external_ext_size))
|
1346 |
|
|
return FALSE;
|
1347 |
|
|
debug->external_ext = external_ext;
|
1348 |
|
|
debug->external_ext_end = external_ext_end;
|
1349 |
|
|
}
|
1350 |
|
|
|
1351 |
|
|
esym->asym.iss = symhdr->issExtMax;
|
1352 |
|
|
|
1353 |
|
|
(*swap_ext_out) (abfd, esym,
|
1354 |
|
|
((char *) debug->external_ext
|
1355 |
|
|
+ symhdr->iextMax * swap->external_ext_size));
|
1356 |
|
|
|
1357 |
|
|
++symhdr->iextMax;
|
1358 |
|
|
|
1359 |
|
|
strcpy (debug->ssext + symhdr->issExtMax, name);
|
1360 |
|
|
symhdr->issExtMax += namelen + 1;
|
1361 |
|
|
|
1362 |
|
|
return TRUE;
|
1363 |
|
|
}
|
1364 |
|
|
|
1365 |
|
|
/* Align the ECOFF debugging information. */
|
1366 |
|
|
|
1367 |
|
|
static void
|
1368 |
|
|
ecoff_align_debug (abfd, debug, swap)
|
1369 |
|
|
bfd *abfd ATTRIBUTE_UNUSED;
|
1370 |
|
|
struct ecoff_debug_info *debug;
|
1371 |
|
|
const struct ecoff_debug_swap *swap;
|
1372 |
|
|
{
|
1373 |
|
|
HDRR * const symhdr = &debug->symbolic_header;
|
1374 |
|
|
bfd_size_type debug_align, aux_align, rfd_align;
|
1375 |
|
|
size_t add;
|
1376 |
|
|
|
1377 |
|
|
/* Adjust the counts so that structures are aligned. */
|
1378 |
|
|
debug_align = swap->debug_align;
|
1379 |
|
|
aux_align = debug_align / sizeof (union aux_ext);
|
1380 |
|
|
rfd_align = debug_align / swap->external_rfd_size;
|
1381 |
|
|
|
1382 |
|
|
add = debug_align - (symhdr->cbLine & (debug_align - 1));
|
1383 |
|
|
if (add != debug_align)
|
1384 |
|
|
{
|
1385 |
|
|
if (debug->line != (unsigned char *) NULL)
|
1386 |
|
|
memset ((PTR) (debug->line + symhdr->cbLine), 0, add);
|
1387 |
|
|
symhdr->cbLine += add;
|
1388 |
|
|
}
|
1389 |
|
|
|
1390 |
|
|
add = debug_align - (symhdr->issMax & (debug_align - 1));
|
1391 |
|
|
if (add != debug_align)
|
1392 |
|
|
{
|
1393 |
|
|
if (debug->ss != (char *) NULL)
|
1394 |
|
|
memset ((PTR) (debug->ss + symhdr->issMax), 0, add);
|
1395 |
|
|
symhdr->issMax += add;
|
1396 |
|
|
}
|
1397 |
|
|
|
1398 |
|
|
add = debug_align - (symhdr->issExtMax & (debug_align - 1));
|
1399 |
|
|
if (add != debug_align)
|
1400 |
|
|
{
|
1401 |
|
|
if (debug->ssext != (char *) NULL)
|
1402 |
|
|
memset ((PTR) (debug->ssext + symhdr->issExtMax), 0, add);
|
1403 |
|
|
symhdr->issExtMax += add;
|
1404 |
|
|
}
|
1405 |
|
|
|
1406 |
|
|
add = aux_align - (symhdr->iauxMax & (aux_align - 1));
|
1407 |
|
|
if (add != aux_align)
|
1408 |
|
|
{
|
1409 |
|
|
if (debug->external_aux != (union aux_ext *) NULL)
|
1410 |
|
|
memset ((PTR) (debug->external_aux + symhdr->iauxMax), 0,
|
1411 |
|
|
add * sizeof (union aux_ext));
|
1412 |
|
|
symhdr->iauxMax += add;
|
1413 |
|
|
}
|
1414 |
|
|
|
1415 |
|
|
add = rfd_align - (symhdr->crfd & (rfd_align - 1));
|
1416 |
|
|
if (add != rfd_align)
|
1417 |
|
|
{
|
1418 |
|
|
if (debug->external_rfd != (PTR) NULL)
|
1419 |
|
|
memset ((PTR) ((char *) debug->external_rfd
|
1420 |
|
|
+ symhdr->crfd * swap->external_rfd_size),
|
1421 |
|
|
0, (size_t) (add * swap->external_rfd_size));
|
1422 |
|
|
symhdr->crfd += add;
|
1423 |
|
|
}
|
1424 |
|
|
}
|
1425 |
|
|
|
1426 |
|
|
/* Return the size required by the ECOFF debugging information. */
|
1427 |
|
|
|
1428 |
|
|
bfd_size_type
|
1429 |
|
|
bfd_ecoff_debug_size (abfd, debug, swap)
|
1430 |
|
|
bfd *abfd;
|
1431 |
|
|
struct ecoff_debug_info *debug;
|
1432 |
|
|
const struct ecoff_debug_swap *swap;
|
1433 |
|
|
{
|
1434 |
|
|
bfd_size_type tot;
|
1435 |
|
|
|
1436 |
|
|
ecoff_align_debug (abfd, debug, swap);
|
1437 |
|
|
tot = swap->external_hdr_size;
|
1438 |
|
|
|
1439 |
|
|
#define ADD(count, size) \
|
1440 |
|
|
tot += debug->symbolic_header.count * size
|
1441 |
|
|
|
1442 |
|
|
ADD (cbLine, sizeof (unsigned char));
|
1443 |
|
|
ADD (idnMax, swap->external_dnr_size);
|
1444 |
|
|
ADD (ipdMax, swap->external_pdr_size);
|
1445 |
|
|
ADD (isymMax, swap->external_sym_size);
|
1446 |
|
|
ADD (ioptMax, swap->external_opt_size);
|
1447 |
|
|
ADD (iauxMax, sizeof (union aux_ext));
|
1448 |
|
|
ADD (issMax, sizeof (char));
|
1449 |
|
|
ADD (issExtMax, sizeof (char));
|
1450 |
|
|
ADD (ifdMax, swap->external_fdr_size);
|
1451 |
|
|
ADD (crfd, swap->external_rfd_size);
|
1452 |
|
|
ADD (iextMax, swap->external_ext_size);
|
1453 |
|
|
|
1454 |
|
|
#undef ADD
|
1455 |
|
|
|
1456 |
|
|
return tot;
|
1457 |
|
|
}
|
1458 |
|
|
|
1459 |
|
|
/* Write out the ECOFF symbolic header, given the file position it is
|
1460 |
|
|
going to be placed at. This assumes that the counts are set
|
1461 |
|
|
correctly. */
|
1462 |
|
|
|
1463 |
|
|
static bfd_boolean
|
1464 |
|
|
ecoff_write_symhdr (abfd, debug, swap, where)
|
1465 |
|
|
bfd *abfd;
|
1466 |
|
|
struct ecoff_debug_info *debug;
|
1467 |
|
|
const struct ecoff_debug_swap *swap;
|
1468 |
|
|
file_ptr where;
|
1469 |
|
|
{
|
1470 |
|
|
HDRR * const symhdr = &debug->symbolic_header;
|
1471 |
|
|
char *buff = NULL;
|
1472 |
|
|
|
1473 |
|
|
ecoff_align_debug (abfd, debug, swap);
|
1474 |
|
|
|
1475 |
|
|
/* Go to the right location in the file. */
|
1476 |
|
|
if (bfd_seek (abfd, where, SEEK_SET) != 0)
|
1477 |
|
|
return FALSE;
|
1478 |
|
|
|
1479 |
|
|
where += swap->external_hdr_size;
|
1480 |
|
|
|
1481 |
|
|
symhdr->magic = swap->sym_magic;
|
1482 |
|
|
|
1483 |
|
|
/* Fill in the file offsets. */
|
1484 |
|
|
#define SET(offset, count, size) \
|
1485 |
|
|
if (symhdr->count == 0) \
|
1486 |
|
|
symhdr->offset = 0; \
|
1487 |
|
|
else \
|
1488 |
|
|
{ \
|
1489 |
|
|
symhdr->offset = where; \
|
1490 |
|
|
where += symhdr->count * size; \
|
1491 |
|
|
}
|
1492 |
|
|
|
1493 |
|
|
SET (cbLineOffset, cbLine, sizeof (unsigned char));
|
1494 |
|
|
SET (cbDnOffset, idnMax, swap->external_dnr_size);
|
1495 |
|
|
SET (cbPdOffset, ipdMax, swap->external_pdr_size);
|
1496 |
|
|
SET (cbSymOffset, isymMax, swap->external_sym_size);
|
1497 |
|
|
SET (cbOptOffset, ioptMax, swap->external_opt_size);
|
1498 |
|
|
SET (cbAuxOffset, iauxMax, sizeof (union aux_ext));
|
1499 |
|
|
SET (cbSsOffset, issMax, sizeof (char));
|
1500 |
|
|
SET (cbSsExtOffset, issExtMax, sizeof (char));
|
1501 |
|
|
SET (cbFdOffset, ifdMax, swap->external_fdr_size);
|
1502 |
|
|
SET (cbRfdOffset, crfd, swap->external_rfd_size);
|
1503 |
|
|
SET (cbExtOffset, iextMax, swap->external_ext_size);
|
1504 |
|
|
#undef SET
|
1505 |
|
|
|
1506 |
|
|
buff = (PTR) bfd_malloc (swap->external_hdr_size);
|
1507 |
|
|
if (buff == NULL && swap->external_hdr_size != 0)
|
1508 |
|
|
goto error_return;
|
1509 |
|
|
|
1510 |
|
|
(*swap->swap_hdr_out) (abfd, symhdr, buff);
|
1511 |
|
|
if (bfd_bwrite (buff, swap->external_hdr_size, abfd)
|
1512 |
|
|
!= swap->external_hdr_size)
|
1513 |
|
|
goto error_return;
|
1514 |
|
|
|
1515 |
|
|
if (buff != NULL)
|
1516 |
|
|
free (buff);
|
1517 |
|
|
return TRUE;
|
1518 |
|
|
error_return:
|
1519 |
|
|
if (buff != NULL)
|
1520 |
|
|
free (buff);
|
1521 |
|
|
return FALSE;
|
1522 |
|
|
}
|
1523 |
|
|
|
1524 |
|
|
/* Write out the ECOFF debugging information. This function assumes
|
1525 |
|
|
that the information (the pointers and counts) in *DEBUG have been
|
1526 |
|
|
set correctly. WHERE is the position in the file to write the
|
1527 |
|
|
information to. This function fills in the file offsets in the
|
1528 |
|
|
symbolic header. */
|
1529 |
|
|
|
1530 |
|
|
bfd_boolean
|
1531 |
|
|
bfd_ecoff_write_debug (abfd, debug, swap, where)
|
1532 |
|
|
bfd *abfd;
|
1533 |
|
|
struct ecoff_debug_info *debug;
|
1534 |
|
|
const struct ecoff_debug_swap *swap;
|
1535 |
|
|
file_ptr where;
|
1536 |
|
|
{
|
1537 |
|
|
HDRR * const symhdr = &debug->symbolic_header;
|
1538 |
|
|
|
1539 |
|
|
if (! ecoff_write_symhdr (abfd, debug, swap, where))
|
1540 |
|
|
return FALSE;
|
1541 |
|
|
|
1542 |
|
|
#define WRITE(ptr, count, size, offset) \
|
1543 |
|
|
BFD_ASSERT (symhdr->offset == 0 \
|
1544 |
|
|
|| (bfd_vma) bfd_tell (abfd) == symhdr->offset); \
|
1545 |
|
|
if (bfd_bwrite ((PTR) debug->ptr, (bfd_size_type) size * symhdr->count, abfd)\
|
1546 |
|
|
!= size * symhdr->count) \
|
1547 |
|
|
return FALSE;
|
1548 |
|
|
|
1549 |
|
|
WRITE (line, cbLine, sizeof (unsigned char), cbLineOffset);
|
1550 |
|
|
WRITE (external_dnr, idnMax, swap->external_dnr_size, cbDnOffset);
|
1551 |
|
|
WRITE (external_pdr, ipdMax, swap->external_pdr_size, cbPdOffset);
|
1552 |
|
|
WRITE (external_sym, isymMax, swap->external_sym_size, cbSymOffset);
|
1553 |
|
|
WRITE (external_opt, ioptMax, swap->external_opt_size, cbOptOffset);
|
1554 |
|
|
WRITE (external_aux, iauxMax, (bfd_size_type) sizeof (union aux_ext),
|
1555 |
|
|
cbAuxOffset);
|
1556 |
|
|
WRITE (ss, issMax, sizeof (char), cbSsOffset);
|
1557 |
|
|
WRITE (ssext, issExtMax, sizeof (char), cbSsExtOffset);
|
1558 |
|
|
WRITE (external_fdr, ifdMax, swap->external_fdr_size, cbFdOffset);
|
1559 |
|
|
WRITE (external_rfd, crfd, swap->external_rfd_size, cbRfdOffset);
|
1560 |
|
|
WRITE (external_ext, iextMax, swap->external_ext_size, cbExtOffset);
|
1561 |
|
|
#undef WRITE
|
1562 |
|
|
|
1563 |
|
|
return TRUE;
|
1564 |
|
|
}
|
1565 |
|
|
|
1566 |
|
|
/* Write out a shuffle list. */
|
1567 |
|
|
|
1568 |
|
|
static bfd_boolean ecoff_write_shuffle
|
1569 |
|
|
PARAMS ((bfd *, const struct ecoff_debug_swap *, struct shuffle *,
|
1570 |
|
|
PTR space));
|
1571 |
|
|
|
1572 |
|
|
static bfd_boolean
|
1573 |
|
|
ecoff_write_shuffle (abfd, swap, shuffle, space)
|
1574 |
|
|
bfd *abfd;
|
1575 |
|
|
const struct ecoff_debug_swap *swap;
|
1576 |
|
|
struct shuffle *shuffle;
|
1577 |
|
|
PTR space;
|
1578 |
|
|
{
|
1579 |
|
|
register struct shuffle *l;
|
1580 |
|
|
unsigned long total;
|
1581 |
|
|
|
1582 |
|
|
total = 0;
|
1583 |
|
|
for (l = shuffle; l != (struct shuffle *) NULL; l = l->next)
|
1584 |
|
|
{
|
1585 |
|
|
if (! l->filep)
|
1586 |
|
|
{
|
1587 |
|
|
if (bfd_bwrite (l->u.memory, (bfd_size_type) l->size, abfd)
|
1588 |
|
|
!= l->size)
|
1589 |
|
|
return FALSE;
|
1590 |
|
|
}
|
1591 |
|
|
else
|
1592 |
|
|
{
|
1593 |
|
|
if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0
|
1594 |
|
|
|| bfd_bread (space, (bfd_size_type) l->size,
|
1595 |
|
|
l->u.file.input_bfd) != l->size
|
1596 |
|
|
|| bfd_bwrite (space, (bfd_size_type) l->size, abfd) != l->size)
|
1597 |
|
|
return FALSE;
|
1598 |
|
|
}
|
1599 |
|
|
total += l->size;
|
1600 |
|
|
}
|
1601 |
|
|
|
1602 |
|
|
if ((total & (swap->debug_align - 1)) != 0)
|
1603 |
|
|
{
|
1604 |
|
|
unsigned int i;
|
1605 |
|
|
bfd_byte *s;
|
1606 |
|
|
|
1607 |
|
|
i = swap->debug_align - (total & (swap->debug_align - 1));
|
1608 |
|
|
s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
|
1609 |
|
|
if (s == NULL && i != 0)
|
1610 |
|
|
return FALSE;
|
1611 |
|
|
|
1612 |
|
|
if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
|
1613 |
|
|
{
|
1614 |
|
|
free (s);
|
1615 |
|
|
return FALSE;
|
1616 |
|
|
}
|
1617 |
|
|
free (s);
|
1618 |
|
|
}
|
1619 |
|
|
|
1620 |
|
|
return TRUE;
|
1621 |
|
|
}
|
1622 |
|
|
|
1623 |
|
|
/* Write out debugging information using accumulated linker
|
1624 |
|
|
information. */
|
1625 |
|
|
|
1626 |
|
|
bfd_boolean
|
1627 |
|
|
bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
|
1628 |
|
|
PTR handle;
|
1629 |
|
|
bfd *abfd;
|
1630 |
|
|
struct ecoff_debug_info *debug;
|
1631 |
|
|
const struct ecoff_debug_swap *swap;
|
1632 |
|
|
struct bfd_link_info *info;
|
1633 |
|
|
file_ptr where;
|
1634 |
|
|
{
|
1635 |
|
|
struct accumulate *ainfo = (struct accumulate *) handle;
|
1636 |
|
|
PTR space = NULL;
|
1637 |
|
|
bfd_size_type amt;
|
1638 |
|
|
|
1639 |
|
|
if (! ecoff_write_symhdr (abfd, debug, swap, where))
|
1640 |
|
|
goto error_return;
|
1641 |
|
|
|
1642 |
|
|
amt = ainfo->largest_file_shuffle;
|
1643 |
|
|
space = (PTR) bfd_malloc (amt);
|
1644 |
|
|
if (space == NULL && ainfo->largest_file_shuffle != 0)
|
1645 |
|
|
goto error_return;
|
1646 |
|
|
|
1647 |
|
|
if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space)
|
1648 |
|
|
|| ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space)
|
1649 |
|
|
|| ! ecoff_write_shuffle (abfd, swap, ainfo->sym, space)
|
1650 |
|
|
|| ! ecoff_write_shuffle (abfd, swap, ainfo->opt, space)
|
1651 |
|
|
|| ! ecoff_write_shuffle (abfd, swap, ainfo->aux, space))
|
1652 |
|
|
goto error_return;
|
1653 |
|
|
|
1654 |
|
|
/* The string table is written out from the hash table if this is a
|
1655 |
|
|
final link. */
|
1656 |
|
|
if (info->relocatable)
|
1657 |
|
|
{
|
1658 |
|
|
BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL);
|
1659 |
|
|
if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space))
|
1660 |
|
|
goto error_return;
|
1661 |
|
|
}
|
1662 |
|
|
else
|
1663 |
|
|
{
|
1664 |
|
|
unsigned long total;
|
1665 |
|
|
bfd_byte null;
|
1666 |
|
|
struct string_hash_entry *sh;
|
1667 |
|
|
|
1668 |
|
|
BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
|
1669 |
|
|
null = 0;
|
1670 |
|
|
if (bfd_bwrite ((PTR) &null, (bfd_size_type) 1, abfd) != 1)
|
1671 |
|
|
goto error_return;
|
1672 |
|
|
total = 1;
|
1673 |
|
|
BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1);
|
1674 |
|
|
for (sh = ainfo->ss_hash;
|
1675 |
|
|
sh != (struct string_hash_entry *) NULL;
|
1676 |
|
|
sh = sh->next)
|
1677 |
|
|
{
|
1678 |
|
|
size_t len;
|
1679 |
|
|
|
1680 |
|
|
len = strlen (sh->root.string);
|
1681 |
|
|
amt = len + 1;
|
1682 |
|
|
if (bfd_bwrite ((PTR) sh->root.string, amt, abfd) != amt)
|
1683 |
|
|
goto error_return;
|
1684 |
|
|
total += len + 1;
|
1685 |
|
|
}
|
1686 |
|
|
|
1687 |
|
|
if ((total & (swap->debug_align - 1)) != 0)
|
1688 |
|
|
{
|
1689 |
|
|
unsigned int i;
|
1690 |
|
|
bfd_byte *s;
|
1691 |
|
|
|
1692 |
|
|
i = swap->debug_align - (total & (swap->debug_align - 1));
|
1693 |
|
|
s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
|
1694 |
|
|
if (s == NULL && i != 0)
|
1695 |
|
|
goto error_return;
|
1696 |
|
|
|
1697 |
|
|
if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
|
1698 |
|
|
{
|
1699 |
|
|
free (s);
|
1700 |
|
|
goto error_return;
|
1701 |
|
|
}
|
1702 |
|
|
free (s);
|
1703 |
|
|
}
|
1704 |
|
|
}
|
1705 |
|
|
|
1706 |
|
|
/* The external strings and symbol are not converted over to using
|
1707 |
|
|
shuffles. FIXME: They probably should be. */
|
1708 |
|
|
amt = debug->symbolic_header.issExtMax;
|
1709 |
|
|
if (bfd_bwrite (debug->ssext, amt, abfd) != amt)
|
1710 |
|
|
goto error_return;
|
1711 |
|
|
if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0)
|
1712 |
|
|
{
|
1713 |
|
|
unsigned int i;
|
1714 |
|
|
bfd_byte *s;
|
1715 |
|
|
|
1716 |
|
|
i = (swap->debug_align
|
1717 |
|
|
- (debug->symbolic_header.issExtMax & (swap->debug_align - 1)));
|
1718 |
|
|
s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
|
1719 |
|
|
if (s == NULL && i != 0)
|
1720 |
|
|
goto error_return;
|
1721 |
|
|
|
1722 |
|
|
if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
|
1723 |
|
|
{
|
1724 |
|
|
free (s);
|
1725 |
|
|
goto error_return;
|
1726 |
|
|
}
|
1727 |
|
|
free (s);
|
1728 |
|
|
}
|
1729 |
|
|
|
1730 |
|
|
if (! ecoff_write_shuffle (abfd, swap, ainfo->fdr, space)
|
1731 |
|
|
|| ! ecoff_write_shuffle (abfd, swap, ainfo->rfd, space))
|
1732 |
|
|
goto error_return;
|
1733 |
|
|
|
1734 |
|
|
BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0
|
1735 |
|
|
|| (debug->symbolic_header.cbExtOffset
|
1736 |
|
|
== (bfd_vma) bfd_tell (abfd)));
|
1737 |
|
|
|
1738 |
|
|
amt = debug->symbolic_header.iextMax * swap->external_ext_size;
|
1739 |
|
|
if (bfd_bwrite (debug->external_ext, amt, abfd) != amt)
|
1740 |
|
|
goto error_return;
|
1741 |
|
|
|
1742 |
|
|
if (space != NULL)
|
1743 |
|
|
free (space);
|
1744 |
|
|
return TRUE;
|
1745 |
|
|
|
1746 |
|
|
error_return:
|
1747 |
|
|
if (space != NULL)
|
1748 |
|
|
free (space);
|
1749 |
|
|
return FALSE;
|
1750 |
|
|
}
|
1751 |
|
|
|
1752 |
|
|
/* Handle the find_nearest_line function for both ECOFF and MIPS ELF
|
1753 |
|
|
files. */
|
1754 |
|
|
|
1755 |
|
|
/* Compare FDR entries. This is called via qsort. */
|
1756 |
|
|
|
1757 |
|
|
static int
|
1758 |
|
|
cmp_fdrtab_entry (leftp, rightp)
|
1759 |
|
|
const PTR leftp;
|
1760 |
|
|
const PTR rightp;
|
1761 |
|
|
{
|
1762 |
|
|
const struct ecoff_fdrtab_entry *lp =
|
1763 |
|
|
(const struct ecoff_fdrtab_entry *) leftp;
|
1764 |
|
|
const struct ecoff_fdrtab_entry *rp =
|
1765 |
|
|
(const struct ecoff_fdrtab_entry *) rightp;
|
1766 |
|
|
|
1767 |
|
|
if (lp->base_addr < rp->base_addr)
|
1768 |
|
|
return -1;
|
1769 |
|
|
if (lp->base_addr > rp->base_addr)
|
1770 |
|
|
return 1;
|
1771 |
|
|
return 0;
|
1772 |
|
|
}
|
1773 |
|
|
|
1774 |
|
|
/* Each file descriptor (FDR) has a memory address, to simplify
|
1775 |
|
|
looking up an FDR by address, we build a table covering all FDRs
|
1776 |
|
|
that have a least one procedure descriptor in them. The final
|
1777 |
|
|
table will be sorted by address so we can look it up via binary
|
1778 |
|
|
search. */
|
1779 |
|
|
|
1780 |
|
|
static bfd_boolean
|
1781 |
|
|
mk_fdrtab (abfd, debug_info, debug_swap, line_info)
|
1782 |
|
|
bfd *abfd;
|
1783 |
|
|
struct ecoff_debug_info * const debug_info;
|
1784 |
|
|
const struct ecoff_debug_swap * const debug_swap;
|
1785 |
|
|
struct ecoff_find_line *line_info;
|
1786 |
|
|
{
|
1787 |
|
|
struct ecoff_fdrtab_entry *tab;
|
1788 |
|
|
FDR *fdr_ptr;
|
1789 |
|
|
FDR *fdr_start;
|
1790 |
|
|
FDR *fdr_end;
|
1791 |
|
|
bfd_boolean stabs;
|
1792 |
|
|
long len;
|
1793 |
|
|
bfd_size_type amt;
|
1794 |
|
|
|
1795 |
|
|
fdr_start = debug_info->fdr;
|
1796 |
|
|
fdr_end = fdr_start + debug_info->symbolic_header.ifdMax;
|
1797 |
|
|
|
1798 |
|
|
/* First, let's see how long the table needs to be. */
|
1799 |
|
|
for (len = 0, fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
|
1800 |
|
|
{
|
1801 |
|
|
if (fdr_ptr->cpd == 0) /* Skip FDRs that have no PDRs. */
|
1802 |
|
|
continue;
|
1803 |
|
|
++len;
|
1804 |
|
|
}
|
1805 |
|
|
|
1806 |
|
|
/* Now, create and fill in the table. */
|
1807 |
|
|
amt = (bfd_size_type) len * sizeof (struct ecoff_fdrtab_entry);
|
1808 |
|
|
line_info->fdrtab = (struct ecoff_fdrtab_entry*) bfd_zalloc (abfd, amt);
|
1809 |
|
|
if (line_info->fdrtab == NULL)
|
1810 |
|
|
return FALSE;
|
1811 |
|
|
line_info->fdrtab_len = len;
|
1812 |
|
|
|
1813 |
|
|
tab = line_info->fdrtab;
|
1814 |
|
|
for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
|
1815 |
|
|
{
|
1816 |
|
|
if (fdr_ptr->cpd == 0)
|
1817 |
|
|
continue;
|
1818 |
|
|
|
1819 |
|
|
/* Check whether this file has stabs debugging information. In
|
1820 |
|
|
a file with stabs debugging information, the second local
|
1821 |
|
|
symbol is named @stabs. */
|
1822 |
|
|
stabs = FALSE;
|
1823 |
|
|
if (fdr_ptr->csym >= 2)
|
1824 |
|
|
{
|
1825 |
|
|
char *sym_ptr;
|
1826 |
|
|
SYMR sym;
|
1827 |
|
|
|
1828 |
|
|
sym_ptr = ((char *) debug_info->external_sym
|
1829 |
|
|
+ (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size);
|
1830 |
|
|
(*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
|
1831 |
|
|
if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss,
|
1832 |
|
|
STABS_SYMBOL) == 0)
|
1833 |
|
|
stabs = TRUE;
|
1834 |
|
|
}
|
1835 |
|
|
|
1836 |
|
|
if (!stabs)
|
1837 |
|
|
{
|
1838 |
|
|
/* eraxxon: There are at least two problems with this computation:
|
1839 |
|
|
1) PDRs do *not* contain offsets but full vma's; and typically the
|
1840 |
|
|
address of the first PDR is the address of the FDR, which will
|
1841 |
|
|
make (most) of the results of the original computation 0!
|
1842 |
|
|
2) Once in a wacky while, the Compaq compiler generated PDR
|
1843 |
|
|
addresses do not equal the FDR vma, but they (the PDR address)
|
1844 |
|
|
are still vma's and not offsets. Cf. comments in
|
1845 |
|
|
'lookup_line'. */
|
1846 |
|
|
/* The address of the first PDR is the offset of that
|
1847 |
|
|
procedure relative to the beginning of file FDR. */
|
1848 |
|
|
tab->base_addr = fdr_ptr->adr;
|
1849 |
|
|
}
|
1850 |
|
|
else
|
1851 |
|
|
{
|
1852 |
|
|
/* XXX I don't know about stabs, so this is a guess
|
1853 |
|
|
(davidm@cs.arizona.edu). */
|
1854 |
|
|
tab->base_addr = fdr_ptr->adr;
|
1855 |
|
|
}
|
1856 |
|
|
tab->fdr = fdr_ptr;
|
1857 |
|
|
++tab;
|
1858 |
|
|
}
|
1859 |
|
|
|
1860 |
|
|
/* Finally, the table is sorted in increasing memory-address order.
|
1861 |
|
|
The table is mostly sorted already, but there are cases (e.g.,
|
1862 |
|
|
static functions in include files), where this does not hold.
|
1863 |
|
|
Use "odump -PFv" to verify... */
|
1864 |
|
|
qsort ((PTR) line_info->fdrtab, (size_t) len,
|
1865 |
|
|
sizeof (struct ecoff_fdrtab_entry), cmp_fdrtab_entry);
|
1866 |
|
|
|
1867 |
|
|
return TRUE;
|
1868 |
|
|
}
|
1869 |
|
|
|
1870 |
|
|
/* Return index of first FDR that covers to OFFSET. */
|
1871 |
|
|
|
1872 |
|
|
static long
|
1873 |
|
|
fdrtab_lookup (line_info, offset)
|
1874 |
|
|
struct ecoff_find_line *line_info;
|
1875 |
|
|
bfd_vma offset;
|
1876 |
|
|
{
|
1877 |
|
|
long low, high, len;
|
1878 |
|
|
long mid = -1;
|
1879 |
|
|
struct ecoff_fdrtab_entry *tab;
|
1880 |
|
|
|
1881 |
|
|
len = line_info->fdrtab_len;
|
1882 |
|
|
if (len == 0)
|
1883 |
|
|
return -1;
|
1884 |
|
|
|
1885 |
|
|
tab = line_info->fdrtab;
|
1886 |
|
|
for (low = 0, high = len - 1 ; low != high ;)
|
1887 |
|
|
{
|
1888 |
|
|
mid = (high + low) / 2;
|
1889 |
|
|
if (offset >= tab[mid].base_addr && offset < tab[mid + 1].base_addr)
|
1890 |
|
|
goto find_min;
|
1891 |
|
|
|
1892 |
|
|
if (tab[mid].base_addr > offset)
|
1893 |
|
|
high = mid;
|
1894 |
|
|
else
|
1895 |
|
|
low = mid + 1;
|
1896 |
|
|
}
|
1897 |
|
|
|
1898 |
|
|
/* eraxxon: at this point 'offset' is either lower than the lowest entry or
|
1899 |
|
|
higher than the highest entry. In the former case high = low = mid = 0;
|
1900 |
|
|
we want to return -1. In the latter case, low = high and mid = low - 1;
|
1901 |
|
|
we want to return the index of the highest entry. Only in former case
|
1902 |
|
|
will the following 'catch-all' test be true. */
|
1903 |
|
|
++mid;
|
1904 |
|
|
|
1905 |
|
|
/* Last entry is catch-all for all higher addresses. */
|
1906 |
|
|
if (offset < tab[mid].base_addr)
|
1907 |
|
|
return -1;
|
1908 |
|
|
|
1909 |
|
|
find_min:
|
1910 |
|
|
|
1911 |
|
|
/* eraxxon: There may be multiple FDRs in the table with the
|
1912 |
|
|
same base_addr; make sure that we are at the first one. */
|
1913 |
|
|
while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr)
|
1914 |
|
|
--mid;
|
1915 |
|
|
|
1916 |
|
|
return mid;
|
1917 |
|
|
}
|
1918 |
|
|
|
1919 |
|
|
/* Look up a line given an address, storing the information in
|
1920 |
|
|
LINE_INFO->cache. */
|
1921 |
|
|
|
1922 |
|
|
static bfd_boolean
|
1923 |
|
|
lookup_line (abfd, debug_info, debug_swap, line_info)
|
1924 |
|
|
bfd *abfd;
|
1925 |
|
|
struct ecoff_debug_info * const debug_info;
|
1926 |
|
|
const struct ecoff_debug_swap * const debug_swap;
|
1927 |
|
|
struct ecoff_find_line *line_info;
|
1928 |
|
|
{
|
1929 |
|
|
struct ecoff_fdrtab_entry *tab;
|
1930 |
|
|
bfd_vma offset;
|
1931 |
|
|
bfd_boolean stabs;
|
1932 |
|
|
FDR *fdr_ptr;
|
1933 |
|
|
int i;
|
1934 |
|
|
|
1935 |
|
|
/* eraxxon: note that 'offset' is the full vma, not a section offset. */
|
1936 |
|
|
offset = line_info->cache.start;
|
1937 |
|
|
|
1938 |
|
|
/* Build FDR table (sorted by object file's base-address) if we
|
1939 |
|
|
don't have it already. */
|
1940 |
|
|
if (line_info->fdrtab == NULL
|
1941 |
|
|
&& !mk_fdrtab (abfd, debug_info, debug_swap, line_info))
|
1942 |
|
|
return FALSE;
|
1943 |
|
|
|
1944 |
|
|
tab = line_info->fdrtab;
|
1945 |
|
|
|
1946 |
|
|
/* Find first FDR for address OFFSET. */
|
1947 |
|
|
i = fdrtab_lookup (line_info, offset);
|
1948 |
|
|
if (i < 0)
|
1949 |
|
|
return FALSE; /* no FDR, no fun... */
|
1950 |
|
|
|
1951 |
|
|
/* eraxxon: 'fdrtab_lookup' doesn't give what we want, at least for Compaq's
|
1952 |
|
|
C++ compiler 6.2. Consider three FDRs with starting addresses of x, y,
|
1953 |
|
|
and z, respectively, such that x < y < z. Assume further that
|
1954 |
|
|
y < 'offset' < z. It is possible at times that the PDR for 'offset' is
|
1955 |
|
|
associated with FDR x and *not* with FDR y. Erg!!
|
1956 |
|
|
|
1957 |
|
|
From a binary dump of my C++ test case 'moo' using Compaq's coffobjanl
|
1958 |
|
|
(output format has been edited for our purposes):
|
1959 |
|
|
|
1960 |
|
|
FDR [2]: (main.C): First instruction: 0x12000207c <x>
|
1961 |
|
|
PDR [5] for File [2]: LoopTest__Xv <0x1200020a0> (a)
|
1962 |
|
|
PDR [7] for File [2]: foo__Xv <0x120002168>
|
1963 |
|
|
FDR [1]: (-1): First instruction: 0x1200020e8 <y>
|
1964 |
|
|
PDR [3] for File [1]: <0x120001ad0> (b)
|
1965 |
|
|
FDR [6]: (-1): First instruction: 0x1200026f0 <z>
|
1966 |
|
|
|
1967 |
|
|
(a) In the case of PDR5, the vma is such that the first few instructions
|
1968 |
|
|
of the procedure can be found. But since the size of this procedure is
|
1969 |
|
|
160b, the vma will soon cross into the 'address space' of FDR1 and no
|
1970 |
|
|
debugging info will be found. How repugnant!
|
1971 |
|
|
|
1972 |
|
|
(b) It is also possible for a PDR to have a *lower* vma than its associated
|
1973 |
|
|
FDR; see FDR1 and PDR3. Gross!
|
1974 |
|
|
|
1975 |
|
|
Since the FDRs that are causing so much havok (in this case) 1) do not
|
1976 |
|
|
describe actual files (fdr.rss == -1), and 2) contain only compiler
|
1977 |
|
|
generated routines, I thought a simple fix would be to exclude them from
|
1978 |
|
|
the FDR table in 'mk_fdrtab'. But, besides not knowing for certain
|
1979 |
|
|
whether this would be correct, it creates an additional problem. If we
|
1980 |
|
|
happen to ask for source file info on a compiler generated (procedure)
|
1981 |
|
|
symbol -- which is still in the symbol table -- the result can be
|
1982 |
|
|
information from a real procedure! This is because compiler generated
|
1983 |
|
|
procedures with vma's higher than the last FDR in the fdr table will be
|
1984 |
|
|
associated with a PDR from this FDR, specifically the PDR with the
|
1985 |
|
|
highest vma. This wasn't a problem before, because each procedure had a
|
1986 |
|
|
PDR. (Yes, this problem could be eliminated if we kept the size of the
|
1987 |
|
|
last PDR around, but things are already getting ugly).
|
1988 |
|
|
|
1989 |
|
|
Probably, a better solution would be to have a sorted PDR table. Each
|
1990 |
|
|
PDR would have a pointer to its FDR so file information could still be
|
1991 |
|
|
obtained. A FDR table could still be constructed if necessary -- since
|
1992 |
|
|
it only contains pointers, not much extra memory would be used -- but
|
1993 |
|
|
the PDR table would be searched to locate debugging info.
|
1994 |
|
|
|
1995 |
|
|
There is still at least one remaining issue. Sometimes a FDR can have a
|
1996 |
|
|
bogus name, but contain PDRs that should belong to another FDR with a
|
1997 |
|
|
real name. E.g:
|
1998 |
|
|
|
1999 |
|
|
FDR [3]: 0000000120001b50 (/home/.../Array.H~alt~deccxx_5E5A62AD)
|
2000 |
|
|
PDR [a] for File [3]: 0000000120001b50
|
2001 |
|
|
PDR [b] for File [3]: 0000000120001cf0
|
2002 |
|
|
PDR [c] for File [3]: 0000000120001dc8
|
2003 |
|
|
PDR [d] for File [3]: 0000000120001e40
|
2004 |
|
|
PDR [e] for File [3]: 0000000120001eb8
|
2005 |
|
|
PDR [f] for File [3]: 0000000120001f4c
|
2006 |
|
|
FDR [4]: 0000000120001b50 (/home/.../Array.H)
|
2007 |
|
|
|
2008 |
|
|
Here, FDR4 has the correct name, but should (seemingly) contain PDRa-f.
|
2009 |
|
|
The symbol table for PDR4 does contain symbols for PDRa-f, but so does
|
2010 |
|
|
the symbol table for FDR3. However the former is different; perhaps this
|
2011 |
|
|
can be detected easily. (I'm not sure at this point.) This problem only
|
2012 |
|
|
seems to be associated with files with templates. I am assuming the idea
|
2013 |
|
|
is that there is a 'fake' FDR (with PDRs) for each differently typed set
|
2014 |
|
|
of templates that must be generated. Currently, FDR4 is completely
|
2015 |
|
|
excluded from the FDR table in 'mk_fdrtab' because it contains no PDRs.
|
2016 |
|
|
|
2017 |
|
|
Since I don't have time to prepare a real fix for this right now, be
|
2018 |
|
|
prepared for 'A Horrible Hack' to force the inspection of all non-stabs
|
2019 |
|
|
FDRs. It's coming... */
|
2020 |
|
|
fdr_ptr = tab[i].fdr;
|
2021 |
|
|
|
2022 |
|
|
/* Check whether this file has stabs debugging information. In a
|
2023 |
|
|
file with stabs debugging information, the second local symbol is
|
2024 |
|
|
named @stabs. */
|
2025 |
|
|
stabs = FALSE;
|
2026 |
|
|
if (fdr_ptr->csym >= 2)
|
2027 |
|
|
{
|
2028 |
|
|
char *sym_ptr;
|
2029 |
|
|
SYMR sym;
|
2030 |
|
|
|
2031 |
|
|
sym_ptr = ((char *) debug_info->external_sym
|
2032 |
|
|
+ (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size);
|
2033 |
|
|
(*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
|
2034 |
|
|
if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss,
|
2035 |
|
|
STABS_SYMBOL) == 0)
|
2036 |
|
|
stabs = TRUE;
|
2037 |
|
|
}
|
2038 |
|
|
|
2039 |
|
|
if (!stabs)
|
2040 |
|
|
{
|
2041 |
|
|
bfd_size_type external_pdr_size;
|
2042 |
|
|
char *pdr_ptr;
|
2043 |
|
|
char *best_pdr = NULL;
|
2044 |
|
|
FDR *best_fdr;
|
2045 |
|
|
bfd_signed_vma best_dist = -1;
|
2046 |
|
|
PDR pdr;
|
2047 |
|
|
unsigned char *line_ptr;
|
2048 |
|
|
unsigned char *line_end;
|
2049 |
|
|
int lineno;
|
2050 |
|
|
/* This file uses ECOFF debugging information. Each FDR has a
|
2051 |
|
|
list of procedure descriptors (PDR). The address in the FDR
|
2052 |
|
|
is the absolute address of the first procedure. The address
|
2053 |
|
|
in the first PDR gives the offset of that procedure relative
|
2054 |
|
|
to the object file's base-address. The addresses in
|
2055 |
|
|
subsequent PDRs specify each procedure's address relative to
|
2056 |
|
|
the object file's base-address. To make things more juicy,
|
2057 |
|
|
whenever the PROF bit in the PDR is set, the real entry point
|
2058 |
|
|
of the procedure may be 16 bytes below what would normally be
|
2059 |
|
|
the procedure's entry point. Instead, DEC came up with a
|
2060 |
|
|
wicked scheme to create profiled libraries "on the fly":
|
2061 |
|
|
instead of shipping a regular and a profiled version of each
|
2062 |
|
|
library, they insert 16 bytes of unused space in front of
|
2063 |
|
|
each procedure and set the "prof" bit in the PDR to indicate
|
2064 |
|
|
that there is a gap there (this is done automagically by "as"
|
2065 |
|
|
when option "-pg" is specified). Thus, normally, you link
|
2066 |
|
|
against such a library and, except for lots of 16 byte gaps
|
2067 |
|
|
between functions, things will behave as usual. However,
|
2068 |
|
|
when invoking "ld" with option "-pg", it will fill those gaps
|
2069 |
|
|
with code that calls mcount(). It then moves the function's
|
2070 |
|
|
entry point down by 16 bytes, and out pops a binary that has
|
2071 |
|
|
all functions profiled.
|
2072 |
|
|
|
2073 |
|
|
NOTE: Neither FDRs nor PDRs are strictly sorted in memory
|
2074 |
|
|
order. For example, when including header-files that
|
2075 |
|
|
define functions, the FDRs follow behind the including
|
2076 |
|
|
file, even though their code may have been generated at
|
2077 |
|
|
a lower address. File coff-alpha.c from libbfd
|
2078 |
|
|
illustrates this (use "odump -PFv" to look at a file's
|
2079 |
|
|
FDR/PDR). Similarly, PDRs are sometimes out of order
|
2080 |
|
|
as well. An example of this is OSF/1 v3.0 libc's
|
2081 |
|
|
malloc.c. I'm not sure why this happens, but it could
|
2082 |
|
|
be due to optimizations that reorder a function's
|
2083 |
|
|
position within an object-file.
|
2084 |
|
|
|
2085 |
|
|
Strategy:
|
2086 |
|
|
|
2087 |
|
|
On the first call to this function, we build a table of FDRs
|
2088 |
|
|
that is sorted by the base-address of the object-file the FDR
|
2089 |
|
|
is referring to. Notice that each object-file may contain
|
2090 |
|
|
code from multiple source files (e.g., due to code defined in
|
2091 |
|
|
include files). Thus, for any given base-address, there may
|
2092 |
|
|
be multiple FDRs (but this case is, fortunately, uncommon).
|
2093 |
|
|
lookup(addr) guarantees to return the first FDR that applies
|
2094 |
|
|
to address ADDR. Thus, after invoking lookup(), we have a
|
2095 |
|
|
list of FDRs that may contain the PDR for ADDR. Next, we
|
2096 |
|
|
walk through the PDRs of these FDRs and locate the one that
|
2097 |
|
|
is closest to ADDR (i.e., for which the difference between
|
2098 |
|
|
ADDR and the PDR's entry point is positive and minimal).
|
2099 |
|
|
Once, the right FDR and PDR are located, we simply walk
|
2100 |
|
|
through the line-number table to lookup the line-number that
|
2101 |
|
|
best matches ADDR. Obviously, things could be sped up by
|
2102 |
|
|
keeping a sorted list of PDRs instead of a sorted list of
|
2103 |
|
|
FDRs. However, this would increase space requirements
|
2104 |
|
|
considerably, which is undesirable. */
|
2105 |
|
|
external_pdr_size = debug_swap->external_pdr_size;
|
2106 |
|
|
|
2107 |
|
|
/* eraxxon: The Horrible Hack: Because of the problems above, set 'i'
|
2108 |
|
|
to 0 so we look through all FDRs.
|
2109 |
|
|
|
2110 |
|
|
Because FDR's without any symbols are assumed to be non-stabs,
|
2111 |
|
|
searching through all FDRs may cause the following code to try to
|
2112 |
|
|
read stabs FDRs as ECOFF ones. However, I don't think this will
|
2113 |
|
|
harm anything. */
|
2114 |
|
|
i = 0;
|
2115 |
|
|
|
2116 |
|
|
/* Search FDR list starting at tab[i] for the PDR that best matches
|
2117 |
|
|
OFFSET. Normally, the FDR list is only one entry long. */
|
2118 |
|
|
best_fdr = NULL;
|
2119 |
|
|
do
|
2120 |
|
|
{
|
2121 |
|
|
/* eraxxon: 'dist' and 'min_dist' can be negative now
|
2122 |
|
|
because we iterate over every FDR rather than just ones
|
2123 |
|
|
with a base address less than or equal to 'offset'. */
|
2124 |
|
|
bfd_signed_vma dist = -1, min_dist = -1;
|
2125 |
|
|
char *pdr_hold;
|
2126 |
|
|
char *pdr_end;
|
2127 |
|
|
|
2128 |
|
|
fdr_ptr = tab[i].fdr;
|
2129 |
|
|
|
2130 |
|
|
pdr_ptr = ((char *) debug_info->external_pdr
|
2131 |
|
|
+ fdr_ptr->ipdFirst * external_pdr_size);
|
2132 |
|
|
pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
|
2133 |
|
|
(*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
|
2134 |
|
|
/* Find PDR that is closest to OFFSET. If pdr.prof is set,
|
2135 |
|
|
the procedure entry-point *may* be 0x10 below pdr.adr. We
|
2136 |
|
|
simply pretend that pdr.prof *implies* a lower entry-point.
|
2137 |
|
|
This is safe because it just means that may identify 4 NOPs
|
2138 |
|
|
in front of the function as belonging to the function. */
|
2139 |
|
|
for (pdr_hold = NULL;
|
2140 |
|
|
pdr_ptr < pdr_end;
|
2141 |
|
|
(pdr_ptr += external_pdr_size,
|
2142 |
|
|
(*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr)))
|
2143 |
|
|
{
|
2144 |
|
|
if (offset >= (pdr.adr - 0x10 * pdr.prof))
|
2145 |
|
|
{
|
2146 |
|
|
dist = offset - (pdr.adr - 0x10 * pdr.prof);
|
2147 |
|
|
|
2148 |
|
|
/* eraxxon: 'dist' can be negative now. Note that
|
2149 |
|
|
'min_dist' can be negative if 'pdr_hold' below is NULL. */
|
2150 |
|
|
if (!pdr_hold || (dist >= 0 && dist < min_dist))
|
2151 |
|
|
{
|
2152 |
|
|
min_dist = dist;
|
2153 |
|
|
pdr_hold = pdr_ptr;
|
2154 |
|
|
}
|
2155 |
|
|
}
|
2156 |
|
|
}
|
2157 |
|
|
|
2158 |
|
|
if (!best_pdr || (min_dist >= 0 && min_dist < best_dist))
|
2159 |
|
|
{
|
2160 |
|
|
best_dist = (bfd_vma) min_dist;
|
2161 |
|
|
best_fdr = fdr_ptr;
|
2162 |
|
|
best_pdr = pdr_hold;
|
2163 |
|
|
}
|
2164 |
|
|
/* Continue looping until base_addr of next entry is different. */
|
2165 |
|
|
}
|
2166 |
|
|
/* eraxxon: We want to iterate over all FDRs.
|
2167 |
|
|
See previous comment about 'fdrtab_lookup'. */
|
2168 |
|
|
while (++i < line_info->fdrtab_len);
|
2169 |
|
|
|
2170 |
|
|
if (!best_fdr || !best_pdr)
|
2171 |
|
|
return FALSE; /* Shouldn't happen... */
|
2172 |
|
|
|
2173 |
|
|
/* Phew, finally we got something that we can hold onto. */
|
2174 |
|
|
fdr_ptr = best_fdr;
|
2175 |
|
|
pdr_ptr = best_pdr;
|
2176 |
|
|
(*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
|
2177 |
|
|
/* Now we can look for the actual line number. The line numbers
|
2178 |
|
|
are stored in a very funky format, which I won't try to
|
2179 |
|
|
describe. The search is bounded by the end of the FDRs line
|
2180 |
|
|
number entries. */
|
2181 |
|
|
line_end = debug_info->line + fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
|
2182 |
|
|
|
2183 |
|
|
/* Make offset relative to procedure entry. */
|
2184 |
|
|
offset -= pdr.adr - 0x10 * pdr.prof;
|
2185 |
|
|
lineno = pdr.lnLow;
|
2186 |
|
|
line_ptr = debug_info->line + fdr_ptr->cbLineOffset + pdr.cbLineOffset;
|
2187 |
|
|
while (line_ptr < line_end)
|
2188 |
|
|
{
|
2189 |
|
|
int delta;
|
2190 |
|
|
unsigned int count;
|
2191 |
|
|
|
2192 |
|
|
delta = *line_ptr >> 4;
|
2193 |
|
|
if (delta >= 0x8)
|
2194 |
|
|
delta -= 0x10;
|
2195 |
|
|
count = (*line_ptr & 0xf) + 1;
|
2196 |
|
|
++line_ptr;
|
2197 |
|
|
if (delta == -8)
|
2198 |
|
|
{
|
2199 |
|
|
delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff);
|
2200 |
|
|
if (delta >= 0x8000)
|
2201 |
|
|
delta -= 0x10000;
|
2202 |
|
|
line_ptr += 2;
|
2203 |
|
|
}
|
2204 |
|
|
lineno += delta;
|
2205 |
|
|
if (offset < count * 4)
|
2206 |
|
|
{
|
2207 |
|
|
line_info->cache.stop += count * 4 - offset;
|
2208 |
|
|
break;
|
2209 |
|
|
}
|
2210 |
|
|
offset -= count * 4;
|
2211 |
|
|
}
|
2212 |
|
|
|
2213 |
|
|
/* If fdr_ptr->rss is -1, then this file does not have full
|
2214 |
|
|
symbols, at least according to gdb/mipsread.c. */
|
2215 |
|
|
if (fdr_ptr->rss == -1)
|
2216 |
|
|
{
|
2217 |
|
|
line_info->cache.filename = NULL;
|
2218 |
|
|
if (pdr.isym == -1)
|
2219 |
|
|
line_info->cache.functionname = NULL;
|
2220 |
|
|
else
|
2221 |
|
|
{
|
2222 |
|
|
EXTR proc_ext;
|
2223 |
|
|
|
2224 |
|
|
(*debug_swap->swap_ext_in)
|
2225 |
|
|
(abfd,
|
2226 |
|
|
((char *) debug_info->external_ext
|
2227 |
|
|
+ pdr.isym * debug_swap->external_ext_size),
|
2228 |
|
|
&proc_ext);
|
2229 |
|
|
line_info->cache.functionname = (debug_info->ssext
|
2230 |
|
|
+ proc_ext.asym.iss);
|
2231 |
|
|
}
|
2232 |
|
|
}
|
2233 |
|
|
else
|
2234 |
|
|
{
|
2235 |
|
|
SYMR proc_sym;
|
2236 |
|
|
|
2237 |
|
|
line_info->cache.filename = (debug_info->ss
|
2238 |
|
|
+ fdr_ptr->issBase
|
2239 |
|
|
+ fdr_ptr->rss);
|
2240 |
|
|
(*debug_swap->swap_sym_in)
|
2241 |
|
|
(abfd,
|
2242 |
|
|
((char *) debug_info->external_sym
|
2243 |
|
|
+ ((fdr_ptr->isymBase + pdr.isym)
|
2244 |
|
|
* debug_swap->external_sym_size)),
|
2245 |
|
|
&proc_sym);
|
2246 |
|
|
line_info->cache.functionname = (debug_info->ss
|
2247 |
|
|
+ fdr_ptr->issBase
|
2248 |
|
|
+ proc_sym.iss);
|
2249 |
|
|
}
|
2250 |
|
|
if (lineno == ilineNil)
|
2251 |
|
|
lineno = 0;
|
2252 |
|
|
line_info->cache.line_num = lineno;
|
2253 |
|
|
}
|
2254 |
|
|
else
|
2255 |
|
|
{
|
2256 |
|
|
bfd_size_type external_sym_size;
|
2257 |
|
|
const char *directory_name;
|
2258 |
|
|
const char *main_file_name;
|
2259 |
|
|
const char *current_file_name;
|
2260 |
|
|
const char *function_name;
|
2261 |
|
|
const char *line_file_name;
|
2262 |
|
|
bfd_vma low_func_vma;
|
2263 |
|
|
bfd_vma low_line_vma;
|
2264 |
|
|
bfd_boolean past_line;
|
2265 |
|
|
bfd_boolean past_fn;
|
2266 |
|
|
char *sym_ptr, *sym_ptr_end;
|
2267 |
|
|
size_t len, funclen;
|
2268 |
|
|
char *buffer = NULL;
|
2269 |
|
|
|
2270 |
|
|
/* This file uses stabs debugging information. When gcc is not
|
2271 |
|
|
optimizing, it will put the line number information before
|
2272 |
|
|
the function name stabs entry. When gcc is optimizing, it
|
2273 |
|
|
will put the stabs entry for all the function first, followed
|
2274 |
|
|
by the line number information. (This appears to happen
|
2275 |
|
|
because of the two output files used by the -mgpopt switch,
|
2276 |
|
|
which is implied by -O). This means that we must keep
|
2277 |
|
|
looking through the symbols until we find both a line number
|
2278 |
|
|
and a function name which are beyond the address we want. */
|
2279 |
|
|
|
2280 |
|
|
line_info->cache.filename = NULL;
|
2281 |
|
|
line_info->cache.functionname = NULL;
|
2282 |
|
|
line_info->cache.line_num = 0;
|
2283 |
|
|
|
2284 |
|
|
directory_name = NULL;
|
2285 |
|
|
main_file_name = NULL;
|
2286 |
|
|
current_file_name = NULL;
|
2287 |
|
|
function_name = NULL;
|
2288 |
|
|
line_file_name = NULL;
|
2289 |
|
|
low_func_vma = 0;
|
2290 |
|
|
low_line_vma = 0;
|
2291 |
|
|
past_line = FALSE;
|
2292 |
|
|
past_fn = FALSE;
|
2293 |
|
|
|
2294 |
|
|
external_sym_size = debug_swap->external_sym_size;
|
2295 |
|
|
|
2296 |
|
|
sym_ptr = ((char *) debug_info->external_sym
|
2297 |
|
|
+ (fdr_ptr->isymBase + 2) * external_sym_size);
|
2298 |
|
|
sym_ptr_end = sym_ptr + (fdr_ptr->csym - 2) * external_sym_size;
|
2299 |
|
|
for (;
|
2300 |
|
|
sym_ptr < sym_ptr_end && (! past_line || ! past_fn);
|
2301 |
|
|
sym_ptr += external_sym_size)
|
2302 |
|
|
{
|
2303 |
|
|
SYMR sym;
|
2304 |
|
|
|
2305 |
|
|
(*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
|
2306 |
|
|
|
2307 |
|
|
if (ECOFF_IS_STAB (&sym))
|
2308 |
|
|
{
|
2309 |
|
|
switch (ECOFF_UNMARK_STAB (sym.index))
|
2310 |
|
|
{
|
2311 |
|
|
case N_SO:
|
2312 |
|
|
main_file_name = current_file_name =
|
2313 |
|
|
debug_info->ss + fdr_ptr->issBase + sym.iss;
|
2314 |
|
|
|
2315 |
|
|
/* Check the next symbol to see if it is also an
|
2316 |
|
|
N_SO symbol. */
|
2317 |
|
|
if (sym_ptr + external_sym_size < sym_ptr_end)
|
2318 |
|
|
{
|
2319 |
|
|
SYMR nextsym;
|
2320 |
|
|
|
2321 |
|
|
(*debug_swap->swap_sym_in) (abfd,
|
2322 |
|
|
sym_ptr + external_sym_size,
|
2323 |
|
|
&nextsym);
|
2324 |
|
|
if (ECOFF_IS_STAB (&nextsym)
|
2325 |
|
|
&& ECOFF_UNMARK_STAB (nextsym.index) == N_SO)
|
2326 |
|
|
{
|
2327 |
|
|
directory_name = current_file_name;
|
2328 |
|
|
main_file_name = current_file_name =
|
2329 |
|
|
debug_info->ss + fdr_ptr->issBase + nextsym.iss;
|
2330 |
|
|
sym_ptr += external_sym_size;
|
2331 |
|
|
}
|
2332 |
|
|
}
|
2333 |
|
|
break;
|
2334 |
|
|
|
2335 |
|
|
case N_SOL:
|
2336 |
|
|
current_file_name =
|
2337 |
|
|
debug_info->ss + fdr_ptr->issBase + sym.iss;
|
2338 |
|
|
break;
|
2339 |
|
|
|
2340 |
|
|
case N_FUN:
|
2341 |
|
|
if (sym.value > offset)
|
2342 |
|
|
past_fn = TRUE;
|
2343 |
|
|
else if (sym.value >= low_func_vma)
|
2344 |
|
|
{
|
2345 |
|
|
low_func_vma = sym.value;
|
2346 |
|
|
function_name =
|
2347 |
|
|
debug_info->ss + fdr_ptr->issBase + sym.iss;
|
2348 |
|
|
}
|
2349 |
|
|
break;
|
2350 |
|
|
}
|
2351 |
|
|
}
|
2352 |
|
|
else if (sym.st == stLabel && sym.index != indexNil)
|
2353 |
|
|
{
|
2354 |
|
|
if (sym.value > offset)
|
2355 |
|
|
past_line = TRUE;
|
2356 |
|
|
else if (sym.value >= low_line_vma)
|
2357 |
|
|
{
|
2358 |
|
|
low_line_vma = sym.value;
|
2359 |
|
|
line_file_name = current_file_name;
|
2360 |
|
|
line_info->cache.line_num = sym.index;
|
2361 |
|
|
}
|
2362 |
|
|
}
|
2363 |
|
|
}
|
2364 |
|
|
|
2365 |
|
|
if (line_info->cache.line_num != 0)
|
2366 |
|
|
main_file_name = line_file_name;
|
2367 |
|
|
|
2368 |
|
|
/* We need to remove the stuff after the colon in the function
|
2369 |
|
|
name. We also need to put the directory name and the file
|
2370 |
|
|
name together. */
|
2371 |
|
|
if (function_name == NULL)
|
2372 |
|
|
len = funclen = 0;
|
2373 |
|
|
else
|
2374 |
|
|
len = funclen = strlen (function_name) + 1;
|
2375 |
|
|
|
2376 |
|
|
if (main_file_name != NULL
|
2377 |
|
|
&& directory_name != NULL
|
2378 |
|
|
&& main_file_name[0] != '/')
|
2379 |
|
|
len += strlen (directory_name) + strlen (main_file_name) + 1;
|
2380 |
|
|
|
2381 |
|
|
if (len != 0)
|
2382 |
|
|
{
|
2383 |
|
|
if (line_info->find_buffer != NULL)
|
2384 |
|
|
free (line_info->find_buffer);
|
2385 |
|
|
buffer = (char *) bfd_malloc ((bfd_size_type) len);
|
2386 |
|
|
if (buffer == NULL)
|
2387 |
|
|
return FALSE;
|
2388 |
|
|
line_info->find_buffer = buffer;
|
2389 |
|
|
}
|
2390 |
|
|
|
2391 |
|
|
if (function_name != NULL)
|
2392 |
|
|
{
|
2393 |
|
|
char *colon;
|
2394 |
|
|
|
2395 |
|
|
strcpy (buffer, function_name);
|
2396 |
|
|
colon = strchr (buffer, ':');
|
2397 |
|
|
if (colon != NULL)
|
2398 |
|
|
*colon = '\0';
|
2399 |
|
|
line_info->cache.functionname = buffer;
|
2400 |
|
|
}
|
2401 |
|
|
|
2402 |
|
|
if (main_file_name != NULL)
|
2403 |
|
|
{
|
2404 |
|
|
if (directory_name == NULL || main_file_name[0] == '/')
|
2405 |
|
|
line_info->cache.filename = main_file_name;
|
2406 |
|
|
else
|
2407 |
|
|
{
|
2408 |
|
|
sprintf (buffer + funclen, "%s%s", directory_name,
|
2409 |
|
|
main_file_name);
|
2410 |
|
|
line_info->cache.filename = buffer + funclen;
|
2411 |
|
|
}
|
2412 |
|
|
}
|
2413 |
|
|
}
|
2414 |
|
|
|
2415 |
|
|
return TRUE;
|
2416 |
|
|
}
|
2417 |
|
|
|
2418 |
|
|
/* Do the work of find_nearest_line. */
|
2419 |
|
|
|
2420 |
|
|
bfd_boolean
|
2421 |
|
|
_bfd_ecoff_locate_line (abfd, section, offset, debug_info, debug_swap,
|
2422 |
|
|
line_info, filename_ptr, functionname_ptr, retline_ptr)
|
2423 |
|
|
bfd *abfd;
|
2424 |
|
|
asection *section;
|
2425 |
|
|
bfd_vma offset;
|
2426 |
|
|
struct ecoff_debug_info * const debug_info;
|
2427 |
|
|
const struct ecoff_debug_swap * const debug_swap;
|
2428 |
|
|
struct ecoff_find_line *line_info;
|
2429 |
|
|
const char **filename_ptr;
|
2430 |
|
|
const char **functionname_ptr;
|
2431 |
|
|
unsigned int *retline_ptr;
|
2432 |
|
|
{
|
2433 |
|
|
offset += section->vma;
|
2434 |
|
|
|
2435 |
|
|
if (line_info->cache.sect == NULL
|
2436 |
|
|
|| line_info->cache.sect != section
|
2437 |
|
|
|| offset < line_info->cache.start
|
2438 |
|
|
|| offset >= line_info->cache.stop)
|
2439 |
|
|
{
|
2440 |
|
|
line_info->cache.sect = section;
|
2441 |
|
|
line_info->cache.start = offset;
|
2442 |
|
|
line_info->cache.stop = offset;
|
2443 |
|
|
if (! lookup_line (abfd, debug_info, debug_swap, line_info))
|
2444 |
|
|
{
|
2445 |
|
|
line_info->cache.sect = NULL;
|
2446 |
|
|
return FALSE;
|
2447 |
|
|
}
|
2448 |
|
|
}
|
2449 |
|
|
|
2450 |
|
|
*filename_ptr = line_info->cache.filename;
|
2451 |
|
|
*functionname_ptr = line_info->cache.functionname;
|
2452 |
|
|
*retline_ptr = line_info->cache.line_num;
|
2453 |
|
|
|
2454 |
|
|
return TRUE;
|
2455 |
|
|
}
|
2456 |
|
|
|
2457 |
|
|
/* These routines copy symbolic information into a memory buffer.
|
2458 |
|
|
|
2459 |
|
|
FIXME: The whole point of the shuffle code is to avoid storing
|
2460 |
|
|
everything in memory, since the linker is such a memory hog. This
|
2461 |
|
|
code makes that effort useless. It is only called by the MIPS ELF
|
2462 |
|
|
code when generating a shared library, so it is not that big a
|
2463 |
|
|
deal, but it should be fixed eventually. */
|
2464 |
|
|
|
2465 |
|
|
/* Collect a shuffle into a memory buffer. */
|
2466 |
|
|
|
2467 |
|
|
static bfd_boolean ecoff_collect_shuffle
|
2468 |
|
|
PARAMS ((struct shuffle *, bfd_byte *));
|
2469 |
|
|
|
2470 |
|
|
static bfd_boolean
|
2471 |
|
|
ecoff_collect_shuffle (l, buff)
|
2472 |
|
|
struct shuffle *l;
|
2473 |
|
|
bfd_byte *buff;
|
2474 |
|
|
{
|
2475 |
|
|
unsigned long total;
|
2476 |
|
|
|
2477 |
|
|
total = 0;
|
2478 |
|
|
for (; l != (struct shuffle *) NULL; l = l->next)
|
2479 |
|
|
{
|
2480 |
|
|
if (! l->filep)
|
2481 |
|
|
memcpy (buff, l->u.memory, l->size);
|
2482 |
|
|
else
|
2483 |
|
|
{
|
2484 |
|
|
if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0
|
2485 |
|
|
|| (bfd_bread (buff, (bfd_size_type) l->size, l->u.file.input_bfd)
|
2486 |
|
|
!= l->size))
|
2487 |
|
|
return FALSE;
|
2488 |
|
|
}
|
2489 |
|
|
total += l->size;
|
2490 |
|
|
buff += l->size;
|
2491 |
|
|
}
|
2492 |
|
|
|
2493 |
|
|
return TRUE;
|
2494 |
|
|
}
|
2495 |
|
|
|
2496 |
|
|
/* Copy PDR information into a memory buffer. */
|
2497 |
|
|
|
2498 |
|
|
bfd_boolean
|
2499 |
|
|
_bfd_ecoff_get_accumulated_pdr (handle, buff)
|
2500 |
|
|
PTR handle;
|
2501 |
|
|
bfd_byte *buff;
|
2502 |
|
|
{
|
2503 |
|
|
struct accumulate *ainfo = (struct accumulate *) handle;
|
2504 |
|
|
|
2505 |
|
|
return ecoff_collect_shuffle (ainfo->pdr, buff);
|
2506 |
|
|
}
|
2507 |
|
|
|
2508 |
|
|
/* Copy symbol information into a memory buffer. */
|
2509 |
|
|
|
2510 |
|
|
bfd_boolean
|
2511 |
|
|
_bfd_ecoff_get_accumulated_sym (handle, buff)
|
2512 |
|
|
PTR handle;
|
2513 |
|
|
bfd_byte *buff;
|
2514 |
|
|
{
|
2515 |
|
|
struct accumulate *ainfo = (struct accumulate *) handle;
|
2516 |
|
|
|
2517 |
|
|
return ecoff_collect_shuffle (ainfo->sym, buff);
|
2518 |
|
|
}
|
2519 |
|
|
|
2520 |
|
|
/* Copy the string table into a memory buffer. */
|
2521 |
|
|
|
2522 |
|
|
bfd_boolean
|
2523 |
|
|
_bfd_ecoff_get_accumulated_ss (handle, buff)
|
2524 |
|
|
PTR handle;
|
2525 |
|
|
bfd_byte *buff;
|
2526 |
|
|
{
|
2527 |
|
|
struct accumulate *ainfo = (struct accumulate *) handle;
|
2528 |
|
|
struct string_hash_entry *sh;
|
2529 |
|
|
unsigned long total;
|
2530 |
|
|
|
2531 |
|
|
/* The string table is written out from the hash table if this is a
|
2532 |
|
|
final link. */
|
2533 |
|
|
BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
|
2534 |
|
|
*buff++ = '\0';
|
2535 |
|
|
total = 1;
|
2536 |
|
|
BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1);
|
2537 |
|
|
for (sh = ainfo->ss_hash;
|
2538 |
|
|
sh != (struct string_hash_entry *) NULL;
|
2539 |
|
|
sh = sh->next)
|
2540 |
|
|
{
|
2541 |
|
|
size_t len;
|
2542 |
|
|
|
2543 |
|
|
len = strlen (sh->root.string);
|
2544 |
|
|
memcpy (buff, (PTR) sh->root.string, len + 1);
|
2545 |
|
|
total += len + 1;
|
2546 |
|
|
buff += len + 1;
|
2547 |
|
|
}
|
2548 |
|
|
|
2549 |
|
|
return TRUE;
|
2550 |
|
|
}
|