Commit | Line | Data |
---|---|---|
71efdf83 ILT |
1 | /* Routines to link ECOFF debugging information. |
2 | Copyright 1993 Free Software Foundation, Inc. | |
3 | Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>. | |
4 | ||
5 | This file is part of BFD, the Binary File Descriptor library. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
21 | #include "bfd.h" | |
22 | #include "sysdep.h" | |
23 | #include "libbfd.h" | |
24 | #include "coff/internal.h" | |
25 | #include "coff/sym.h" | |
26 | #include "coff/symconst.h" | |
27 | #include "coff/ecoff.h" | |
28 | \f | |
29 | static boolean ecoff_add_bytes PARAMS ((char **buf, char **bufend, | |
30 | bfd_size_type need)); | |
31 | static bfd_size_type ecoff_add_string PARAMS ((struct ecoff_debug_info *, | |
32 | FDR *fdr, const char *string)); | |
33 | static void ecoff_align_debug PARAMS ((bfd *abfd, | |
34 | struct ecoff_debug_info *debug, | |
35 | const struct ecoff_debug_swap *swap)); | |
36 | \f | |
37 | /* The minimum amount of data to allocate. */ | |
38 | #define ALLOC_SIZE (4064) | |
39 | ||
40 | /* Add bytes to a buffer. Return success. */ | |
41 | ||
42 | static boolean | |
43 | ecoff_add_bytes (buf, bufend, need) | |
44 | char **buf; | |
45 | char **bufend; | |
46 | bfd_size_type need; | |
47 | { | |
48 | bfd_size_type have; | |
49 | bfd_size_type want; | |
50 | char *newbuf; | |
51 | ||
52 | have = *bufend - *buf; | |
53 | if (have > need) | |
54 | want = ALLOC_SIZE; | |
55 | else | |
56 | { | |
57 | want = need - have; | |
58 | if (want < ALLOC_SIZE) | |
59 | want = ALLOC_SIZE; | |
60 | } | |
61 | if (*buf == NULL) | |
62 | newbuf = (char *) malloc (have + want); | |
63 | else | |
64 | newbuf = (char *) realloc (*buf, have + want); | |
65 | if (newbuf == NULL) | |
66 | { | |
67 | bfd_error = no_memory; | |
68 | return false; | |
69 | } | |
70 | *buf = newbuf; | |
71 | *bufend = *buf + have + want; | |
72 | return true; | |
73 | } | |
74 | ||
75 | /* Accumulate the debugging information from INPUT_BFD into | |
76 | OUTPUT_BFD. The INPUT_DEBUG argument points to some ECOFF | |
77 | debugging information which we want to link into the information | |
78 | pointed to by the OUTPUT_DEBUG argument. OUTPUT_SWAP and | |
79 | INPUT_SWAP point to the swapping information needed. */ | |
80 | ||
81 | boolean | |
82 | bfd_ecoff_debug_accumulate (output_bfd, output_debug, output_swap, | |
83 | input_bfd, input_debug, input_swap, | |
84 | relocateable) | |
85 | bfd *output_bfd; | |
86 | struct ecoff_debug_info *output_debug; | |
87 | const struct ecoff_debug_swap *output_swap; | |
88 | bfd *input_bfd; | |
89 | struct ecoff_debug_info *input_debug; | |
90 | const struct ecoff_debug_swap *input_swap; | |
91 | boolean relocateable; | |
92 | { | |
93 | void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) | |
94 | = input_swap->swap_sym_in; | |
95 | void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) | |
96 | = output_swap->swap_sym_out; | |
97 | void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)) | |
98 | = output_swap->swap_fdr_out; | |
99 | void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR)) | |
100 | = output_swap->swap_rfd_out; | |
101 | HDRR *output_symhdr; | |
102 | HDRR *input_symhdr; | |
103 | bfd_vma section_adjust[scMax]; | |
104 | asection *sec; | |
105 | char *sym_out; | |
106 | char *lraw_src; | |
107 | char *lraw_end; | |
108 | char *fdr_ptr; | |
109 | char *fdr_end; | |
110 | bfd_size_type fdr_add; | |
111 | char *fdr_out; | |
112 | ||
113 | output_symhdr = &output_debug->symbolic_header; | |
114 | input_symhdr = &input_debug->symbolic_header; | |
115 | ||
116 | /* Make sure the buffers are large enough. */ | |
117 | #define CHECK(start, end, count, size) \ | |
118 | if ((char *) output_debug->end - (char *) output_debug->start \ | |
119 | < (output_symhdr->count + input_symhdr->count) * size) \ | |
120 | { \ | |
121 | if (! ecoff_add_bytes ((char **) &output_debug->start, \ | |
122 | (char **) &output_debug->end, \ | |
123 | ((output_symhdr->count \ | |
124 | + input_symhdr->count) \ | |
125 | * size))) \ | |
126 | return false; \ | |
127 | } | |
128 | ||
129 | CHECK (line, line_end, cbLine, sizeof (unsigned char)); | |
130 | #if 0 | |
131 | /* I don't think dense number information is needed. */ | |
132 | CHECK (external_dnr, external_dnr_end, idnMax, | |
133 | output_swap->external_dnr_size); | |
134 | #endif | |
135 | CHECK (external_pdr, external_pdr_end, ipdMax, | |
136 | output_swap->external_pdr_size); | |
137 | CHECK (external_sym, external_sym_end, isymMax, | |
138 | output_swap->external_sym_size); | |
139 | CHECK (external_opt, external_opt_end, ioptMax, | |
140 | output_swap->external_opt_size); | |
141 | CHECK (external_aux, external_aux_end, iauxMax, | |
142 | sizeof (union aux_ext)); | |
143 | CHECK (ss, ss_end, issMax, sizeof (char)); | |
144 | CHECK (external_fdr, external_fdr_end, ifdMax, | |
145 | output_swap->external_fdr_size); | |
146 | ||
147 | /* The RFD's are special, since we create them if needed. */ | |
148 | { | |
149 | bfd_size_type crfd; | |
150 | ||
151 | crfd = input_symhdr->crfd; | |
152 | if (input_symhdr->crfd == 0) | |
153 | input_symhdr->crfd = input_symhdr->ifdMax; | |
154 | CHECK (external_rfd, external_rfd_end, crfd, | |
155 | output_swap->external_rfd_size); | |
156 | input_symhdr->crfd = crfd; | |
157 | } | |
158 | ||
159 | #undef CHECK | |
160 | ||
161 | /* Use section_adjust to hold the value to add to a symbol in a | |
162 | particular section. */ | |
163 | memset ((PTR) section_adjust, 0, sizeof section_adjust); | |
164 | ||
165 | #define SET(name, indx) \ | |
166 | sec = bfd_get_section_by_name (input_bfd, name); \ | |
167 | if (sec != NULL) \ | |
168 | section_adjust[indx] = (sec->output_section->vma \ | |
169 | + sec->output_offset \ | |
170 | - sec->vma); | |
171 | ||
172 | SET (".text", scText); | |
173 | SET (".data", scData); | |
174 | SET (".bss", scBss); | |
175 | SET (".sdata", scSData); | |
176 | SET (".sbss", scSBss); | |
177 | /* scRdata section may be either .rdata or .rodata. */ | |
178 | SET (".rdata", scRData); | |
179 | SET (".rodata", scRData); | |
180 | SET (".init", scInit); | |
181 | SET (".fini", scFini); | |
182 | ||
183 | #undef SET | |
184 | ||
185 | /* Swap in the local symbols, adjust their values, and swap them out | |
186 | again. The external symbols are handled separately. */ | |
187 | sym_out = ((char *) output_debug->external_sym | |
188 | + output_symhdr->isymMax * output_swap->external_sym_size); | |
189 | lraw_src = (char *) input_debug->external_sym; | |
190 | lraw_end = lraw_src + input_symhdr->isymMax * input_swap->external_sym_size; | |
191 | for (; lraw_src < lraw_end; lraw_src += input_swap->external_sym_size) | |
192 | { | |
193 | SYMR internal_sym; | |
194 | ||
195 | (*swap_sym_in) (input_bfd, (PTR) lraw_src, &internal_sym); | |
196 | ||
197 | BFD_ASSERT (internal_sym.sc != scCommon | |
198 | && internal_sym.sc != scSCommon); | |
199 | ||
200 | /* Adjust the symbol value if appropriate. */ | |
201 | switch (internal_sym.st) | |
202 | { | |
203 | case stNil: | |
204 | if (ECOFF_IS_STAB (&internal_sym)) | |
205 | break; | |
206 | /* Fall through. */ | |
207 | case stGlobal: | |
208 | case stStatic: | |
209 | case stLabel: | |
210 | case stProc: | |
211 | case stStaticProc: | |
212 | internal_sym.value += section_adjust[internal_sym.sc]; | |
213 | break; | |
214 | ||
215 | default: | |
216 | break; | |
217 | } | |
218 | ||
219 | (*swap_sym_out) (output_bfd, &internal_sym, sym_out); | |
220 | sym_out += output_swap->external_sym_size; | |
221 | } | |
222 | ||
223 | /* Copy the information that does not need swapping. */ | |
224 | memcpy (output_debug->line + output_symhdr->cbLine, | |
225 | input_debug->line, | |
226 | input_symhdr->cbLine * sizeof (unsigned char)); | |
227 | memcpy (output_debug->external_aux + output_symhdr->iauxMax, | |
228 | input_debug->external_aux, | |
229 | input_symhdr->iauxMax * sizeof (union aux_ext)); | |
230 | memcpy (output_debug->ss + output_symhdr->issMax, | |
231 | input_debug->ss, | |
232 | input_symhdr->issMax * sizeof (char)); | |
233 | ||
234 | /* Some of the information may need to be swapped. */ | |
235 | if (output_bfd->xvec->header_byteorder_big_p | |
236 | == input_bfd->xvec->header_byteorder_big_p) | |
237 | { | |
238 | /* The two BFD's have the same endianness, so memcpy will | |
239 | suffice. */ | |
240 | #if 0 | |
241 | /* I don't think dense number information is needed. */ | |
242 | BFD_ASSERT (output_swap->external_dnr_size | |
243 | == input_swap->external_dnr_size); | |
244 | if (input_symhdr->idnMax > 0) | |
245 | memcpy (((char *) output_debug->external_dnr | |
246 | + output_symhdr->idnMax * output_swap->external_dnr_size), | |
247 | input_debug->external_dnr, | |
248 | input_symhdr->idnMax * output_swap->external_dnr_size); | |
249 | #endif | |
250 | BFD_ASSERT (output_swap->external_pdr_size | |
251 | == input_swap->external_pdr_size); | |
252 | if (input_symhdr->ipdMax > 0) | |
253 | memcpy (((char *) output_debug->external_pdr | |
254 | + output_symhdr->ipdMax * output_swap->external_pdr_size), | |
255 | input_debug->external_pdr, | |
256 | input_symhdr->ipdMax * output_swap->external_pdr_size); | |
257 | BFD_ASSERT (output_swap->external_opt_size | |
258 | == input_swap->external_opt_size); | |
259 | if (input_symhdr->ioptMax > 0) | |
260 | memcpy (((char *) output_debug->external_opt | |
261 | + output_symhdr->ioptMax * output_swap->external_opt_size), | |
262 | input_debug->external_opt, | |
263 | input_symhdr->ioptMax * output_swap->external_opt_size); | |
264 | } | |
265 | else | |
266 | { | |
267 | bfd_size_type outsz, insz; | |
268 | char *in; | |
269 | char *end; | |
270 | char *out; | |
271 | ||
272 | /* The two BFD's have different endianness, so we must swap | |
273 | everything in and out. This code would always work, but it | |
274 | would be slow in the normal case. */ | |
275 | #if 0 | |
276 | /* I don't think dense number information is needed. */ | |
277 | outsz = output_swap->external_dnr_size; | |
278 | insz = input_swap->external_dnr_size; | |
279 | in = (char *) input_debug->external_dnr; | |
280 | end = in + input_symhdr->idnMax * insz; | |
281 | out = ((char *) output_debug->external_dnr | |
282 | + output_symhdr->idnMax * outsz); | |
283 | for (; in < end; in += insz, out += outsz) | |
284 | { | |
285 | DNR dnr; | |
286 | ||
287 | (*input_swap->swap_dnr_in) (input_bfd, in, &dnr); | |
288 | (*output_swap->swap_dnr_out) (output_bfd, &dnr, out); | |
289 | } | |
290 | #endif | |
291 | ||
292 | outsz = output_swap->external_pdr_size; | |
293 | insz = input_swap->external_pdr_size; | |
294 | in = (char *) input_debug->external_pdr; | |
295 | end = in + input_symhdr->ipdMax * insz; | |
296 | out = ((char *) output_debug->external_pdr | |
297 | + output_symhdr->ipdMax * outsz); | |
298 | for (; in < end; in += insz, out += outsz) | |
299 | { | |
300 | PDR pdr; | |
301 | ||
302 | (*input_swap->swap_pdr_in) (input_bfd, in, &pdr); | |
303 | (*output_swap->swap_pdr_out) (output_bfd, &pdr, out); | |
304 | } | |
305 | ||
306 | outsz = output_swap->external_opt_size; | |
307 | insz = input_swap->external_opt_size; | |
308 | in = (char *) input_debug->external_opt; | |
309 | end = in + input_symhdr->ioptMax * insz; | |
310 | out = ((char *) output_debug->external_opt | |
311 | + output_symhdr->ioptMax * outsz); | |
312 | for (; in < end; in += insz, out += outsz) | |
313 | { | |
314 | OPTR opt; | |
315 | ||
316 | (*input_swap->swap_opt_in) (input_bfd, in, &opt); | |
317 | (*output_swap->swap_opt_out) (output_bfd, &opt, out); | |
318 | } | |
319 | } | |
320 | ||
321 | /* Set ifdbase so that the external symbols know how to adjust their | |
322 | ifd values. */ | |
323 | input_debug->ifdbase = output_symhdr->ifdMax; | |
324 | ||
325 | /* We need to handle the FDR's whether they are swapped or not. */ | |
326 | if (input_debug->fdr != (FDR *) NULL) | |
327 | { | |
328 | fdr_ptr = (char *) input_debug->fdr; | |
329 | fdr_add = sizeof (FDR); | |
330 | } | |
331 | else | |
332 | { | |
333 | fdr_ptr = (char *) input_debug->external_fdr; | |
334 | fdr_add = input_swap->external_fdr_size; | |
335 | } | |
336 | fdr_end = fdr_ptr + input_symhdr->ifdMax * fdr_add; | |
337 | fdr_out = ((char *) output_debug->external_fdr | |
338 | + output_symhdr->ifdMax * output_swap->external_fdr_size); | |
339 | for (; | |
340 | fdr_ptr < fdr_end; | |
341 | fdr_ptr += fdr_add, fdr_out += output_swap->external_fdr_size) | |
342 | { | |
343 | FDR fdr; | |
344 | ||
345 | if (input_debug->fdr != (FDR *) NULL) | |
346 | fdr = *(FDR *) fdr_ptr; | |
347 | else | |
348 | (*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr); | |
349 | ||
350 | /* FIXME: It is conceivable that this FDR points to the .init or | |
351 | .fini section, in which case this will not do the right | |
352 | thing. */ | |
353 | fdr.adr += section_adjust[scText]; | |
354 | ||
355 | fdr.issBase += output_symhdr->issMax; | |
356 | fdr.isymBase += output_symhdr->isymMax; | |
357 | fdr.ilineBase += output_symhdr->ilineMax; | |
358 | fdr.ioptBase += output_symhdr->ioptMax; | |
359 | fdr.ipdFirst += output_symhdr->ipdMax; | |
360 | fdr.iauxBase += output_symhdr->iauxMax; | |
361 | fdr.rfdBase += output_symhdr->crfd; | |
362 | ||
363 | /* If there are no RFD's, we are going to add some. We don't | |
364 | want to adjust crfd for this, so that all the FDR's can share | |
365 | the RFD's. */ | |
366 | if (input_symhdr->crfd == 0) | |
367 | fdr.crfd = input_symhdr->ifdMax; | |
368 | ||
369 | if (fdr.cbLine != 0) | |
370 | fdr.cbLineOffset += output_symhdr->cbLine; | |
371 | ||
372 | (*swap_fdr_out) (output_bfd, &fdr, fdr_out); | |
373 | } | |
374 | ||
375 | if (input_symhdr->crfd > 0) | |
376 | { | |
377 | void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)) | |
378 | = input_swap->swap_rfd_in; | |
379 | bfd_size_type outsz, insz; | |
380 | char *rfd_in; | |
381 | char *rfd_end; | |
382 | char *rfd_out; | |
383 | ||
384 | /* Swap and adjust the RFD's. RFD's are only created by the | |
385 | linker, so this will only be necessary if one of the input | |
386 | files is the result of a partial link. Presumably all | |
387 | necessary RFD's are present. */ | |
388 | outsz = output_swap->external_rfd_size; | |
389 | insz = input_swap->external_rfd_size; | |
390 | rfd_in = (char *) input_debug->external_rfd; | |
391 | rfd_end = rfd_in + input_symhdr->crfd * insz; | |
392 | rfd_out = ((char *) output_debug->external_rfd | |
393 | + output_symhdr->crfd * outsz); | |
394 | for (; | |
395 | rfd_in < rfd_end; | |
396 | rfd_in += insz, rfd_out += outsz) | |
397 | { | |
398 | RFDT rfd; | |
399 | ||
400 | (*swap_rfd_in) (input_bfd, rfd_in, &rfd); | |
401 | rfd += output_symhdr->ifdMax; | |
402 | (*swap_rfd_out) (output_bfd, &rfd, rfd_out); | |
403 | } | |
404 | output_symhdr->crfd += input_symhdr->crfd; | |
405 | } | |
406 | else | |
407 | { | |
408 | bfd_size_type outsz; | |
409 | char *rfd_out; | |
410 | char *rfd_end; | |
411 | RFDT rfd; | |
412 | ||
413 | /* Create RFD's. Some of the debugging information includes | |
414 | relative file indices. These indices are taken as indices to | |
415 | the RFD table if there is one, or to the global table if | |
416 | there is not. If we did not create RFD's, we would have to | |
417 | parse and adjust all the debugging information which contains | |
418 | file indices. */ | |
419 | outsz = output_swap->external_rfd_size; | |
420 | rfd = output_symhdr->ifdMax; | |
421 | rfd_out = ((char *) output_debug->external_rfd | |
422 | + output_symhdr->crfd * outsz); | |
423 | rfd_end = (rfd_out + input_symhdr->ifdMax * outsz); | |
424 | for (; rfd_out < rfd_end; rfd_out += outsz, rfd++) | |
425 | (*swap_rfd_out) (output_bfd, &rfd, rfd_out); | |
426 | output_symhdr->crfd += input_symhdr->ifdMax; | |
427 | } | |
428 | ||
429 | /* Update the counts. */ | |
430 | output_symhdr->ilineMax += input_symhdr->ilineMax; | |
431 | output_symhdr->cbLine += input_symhdr->cbLine; | |
432 | #if 0 | |
433 | /* I don't think dense number information is needed. */ | |
434 | output_symhdr->idnMax += input_symhdr->idnMax; | |
435 | #endif | |
436 | output_symhdr->ipdMax += input_symhdr->ipdMax; | |
437 | output_symhdr->isymMax += input_symhdr->isymMax; | |
438 | output_symhdr->ioptMax += input_symhdr->ioptMax; | |
439 | output_symhdr->iauxMax += input_symhdr->iauxMax; | |
440 | output_symhdr->issMax += input_symhdr->issMax; | |
441 | output_symhdr->ifdMax += input_symhdr->ifdMax; | |
442 | ||
443 | return true; | |
444 | } | |
445 | ||
446 | /* Add a string to the debugging information we are accumulating. | |
447 | Return the offset from the fdr string base. */ | |
448 | ||
449 | static bfd_size_type | |
450 | ecoff_add_string (output, fdr, string) | |
451 | struct ecoff_debug_info *output; | |
452 | FDR *fdr; | |
453 | const char *string; | |
454 | { | |
455 | HDRR *symhdr; | |
456 | size_t len; | |
457 | bfd_size_type ret; | |
458 | ||
459 | symhdr = &output->symbolic_header; | |
460 | len = strlen (string); | |
461 | if (output->ss_end - output->ss < symhdr->issMax + len + 1) | |
462 | { | |
463 | if (ecoff_add_bytes (&output->ss, &output->ss_end, | |
464 | symhdr->issMax + len + 1) == false) | |
465 | return -1; | |
466 | } | |
467 | memcpy (output->ss + symhdr->issMax, string, len + 1); | |
468 | ret = fdr->cbSs; | |
469 | symhdr->issMax += len + 1; | |
470 | fdr->cbSs += len + 1; | |
471 | return ret; | |
472 | } | |
473 | ||
474 | /* Add debugging information from a non-ECOFF file. */ | |
475 | ||
476 | boolean | |
477 | bfd_ecoff_debug_link_other (output_bfd, output_debug, output_swap, input_bfd) | |
478 | bfd *output_bfd; | |
479 | struct ecoff_debug_info *output_debug; | |
480 | const struct ecoff_debug_swap *output_swap; | |
481 | bfd *input_bfd; | |
482 | { | |
483 | void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) | |
484 | = output_swap->swap_sym_out; | |
485 | HDRR *output_symhdr = &output_debug->symbolic_header; | |
486 | FDR fdr; | |
487 | asection *sec; | |
488 | asymbol **symbols; | |
489 | asymbol **sym_ptr; | |
490 | asymbol **sym_end; | |
491 | ||
492 | memset (&fdr, 0, sizeof fdr); | |
493 | ||
494 | sec = bfd_get_section_by_name (input_bfd, ".text"); | |
495 | if (sec != NULL) | |
496 | fdr.adr = sec->output_section->vma + sec->output_offset; | |
497 | else | |
498 | { | |
499 | /* FIXME: What about .init or .fini? */ | |
500 | fdr.adr = 0; | |
501 | } | |
502 | ||
503 | fdr.issBase = output_symhdr->issMax; | |
504 | fdr.cbSs = 0; | |
505 | fdr.rss = ecoff_add_string (output_debug, &fdr, | |
506 | bfd_get_filename (input_bfd)); | |
507 | fdr.isymBase = output_symhdr->isymMax; | |
508 | ||
509 | /* Get the local symbols from the input BFD. */ | |
510 | symbols = (asymbol **) bfd_alloc (output_bfd, | |
511 | get_symtab_upper_bound (input_bfd)); | |
512 | if (symbols == (asymbol **) NULL) | |
513 | { | |
514 | bfd_error = no_memory; | |
515 | return false; | |
516 | } | |
517 | sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols); | |
518 | ||
519 | /* Handle the local symbols. Any external symbols are handled | |
520 | separately. */ | |
521 | fdr.csym = 0; | |
522 | for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++) | |
523 | { | |
524 | SYMR internal_sym; | |
525 | ||
526 | if (((*sym_ptr)->flags & BSF_EXPORT) != 0) | |
527 | continue; | |
528 | memset (&internal_sym, 0, sizeof internal_sym); | |
529 | internal_sym.iss = ecoff_add_string (output_debug, &fdr, | |
530 | (*sym_ptr)->name); | |
531 | ||
532 | if (bfd_is_com_section ((*sym_ptr)->section) | |
533 | || (*sym_ptr)->section == &bfd_und_section) | |
534 | internal_sym.value = (*sym_ptr)->value; | |
535 | else | |
536 | internal_sym.value = ((*sym_ptr)->value | |
537 | + (*sym_ptr)->section->output_offset | |
538 | + (*sym_ptr)->section->output_section->vma); | |
539 | internal_sym.st = stNil; | |
540 | internal_sym.sc = scUndefined; | |
541 | internal_sym.index = indexNil; | |
542 | ||
543 | if (((char *) output_debug->external_sym_end | |
544 | - (char *) output_debug->external_sym) | |
545 | < (output_symhdr->isymMax + 1) * output_swap->external_sym_size) | |
546 | { | |
547 | if (! ecoff_add_bytes ((char **) &output_debug->external_sym, | |
548 | (char **) &output_debug->external_sym_end, | |
549 | ((output_symhdr->isymMax + 1) | |
550 | * output_swap->external_sym_size))) | |
551 | return false; | |
552 | } | |
553 | ||
554 | (*swap_sym_out) (output_bfd, &internal_sym, | |
555 | ((char *) output_debug->external_sym | |
556 | + (output_symhdr->isymMax | |
557 | * output_swap->external_sym_size))); | |
558 | ++fdr.csym; | |
559 | ++output_symhdr->isymMax; | |
560 | } | |
561 | ||
562 | bfd_release (output_bfd, (PTR) symbols); | |
563 | ||
564 | if (((char *) output_debug->external_fdr_end | |
565 | - (char *) output_debug->external_fdr) | |
566 | < (output_symhdr->ifdMax + 1) * output_swap->external_fdr_size) | |
567 | { | |
568 | if (! ecoff_add_bytes ((char **) &output_debug->external_fdr, | |
569 | (char **) &output_debug->external_fdr_end, | |
570 | ((output_symhdr->ifdMax + 1) | |
571 | * output_swap->external_fdr_size))) | |
572 | return false; | |
573 | } | |
574 | ||
575 | /* Leave everything else in the FDR zeroed out. This will cause | |
576 | the lang field to be langC. The fBigendian field will | |
577 | indicate little endian format, but it doesn't matter because | |
578 | it only applies to aux fields and there are none. */ | |
579 | (*output_swap->swap_fdr_out) | |
580 | (output_bfd, &fdr, | |
581 | ((char *) output_debug->external_fdr | |
582 | + output_symhdr->ifdMax * output_swap->external_fdr_size)); | |
583 | ++output_symhdr->ifdMax; | |
584 | return true; | |
585 | } | |
586 | ||
587 | /* Set up ECOFF debugging information for the external symbols. */ | |
588 | ||
589 | boolean | |
590 | bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr, | |
591 | set_index) | |
592 | bfd *abfd; | |
593 | struct ecoff_debug_info *debug; | |
594 | const struct ecoff_debug_swap *swap; | |
595 | boolean relocateable; | |
596 | boolean (*get_extr) PARAMS ((asymbol *, EXTR *)); | |
597 | void (*set_index) PARAMS ((asymbol *, bfd_size_type)); | |
598 | { | |
599 | const bfd_size_type external_ext_size = swap->external_ext_size; | |
600 | void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR)) | |
601 | = swap->swap_ext_out; | |
602 | HDRR * const symhdr = &debug->symbolic_header; | |
603 | asymbol **sym_ptr_ptr; | |
604 | size_t c; | |
605 | ||
606 | sym_ptr_ptr = bfd_get_outsymbols (abfd); | |
607 | if (sym_ptr_ptr == NULL) | |
608 | return true; | |
609 | ||
610 | for (c = bfd_get_symcount (abfd); c > 0; c--, sym_ptr_ptr++) | |
611 | { | |
612 | asymbol *sym_ptr; | |
613 | EXTR esym; | |
614 | ||
615 | sym_ptr = *sym_ptr_ptr; | |
616 | ||
617 | /* Get the external symbol information. */ | |
618 | if ((*get_extr) (sym_ptr, &esym) == false) | |
619 | continue; | |
620 | ||
621 | /* If we're producing an executable, move common symbols into | |
622 | bss. */ | |
623 | if (relocateable == false) | |
624 | { | |
625 | if (esym.asym.sc == scCommon) | |
626 | esym.asym.sc = scBss; | |
627 | else if (esym.asym.sc == scSCommon) | |
628 | esym.asym.sc = scSBss; | |
629 | } | |
630 | ||
631 | if (debug->ssext_end - debug->ssext | |
632 | < symhdr->issExtMax + strlen (sym_ptr->name) + 1) | |
633 | { | |
634 | if (ecoff_add_bytes ((char **) &debug->ssext, | |
635 | (char **) &debug->ssext_end, | |
636 | symhdr->issExtMax + strlen (sym_ptr->name) + 1) | |
637 | == false) | |
638 | return false; | |
639 | } | |
640 | if ((char *) debug->external_ext_end - (char *) debug->external_ext | |
641 | < (symhdr->iextMax + 1) * external_ext_size) | |
642 | { | |
643 | if (ecoff_add_bytes ((char **) &debug->external_ext, | |
644 | (char **) &debug->external_ext_end, | |
645 | (symhdr->iextMax + 1) * external_ext_size) | |
646 | == false) | |
647 | return false; | |
648 | } | |
649 | ||
650 | esym.asym.iss = symhdr->issExtMax; | |
651 | ||
652 | if (bfd_is_com_section (sym_ptr->section) | |
653 | || sym_ptr->section == &bfd_und_section) | |
654 | esym.asym.value = sym_ptr->value; | |
655 | else | |
656 | esym.asym.value = (sym_ptr->value | |
657 | + sym_ptr->section->output_offset | |
658 | + sym_ptr->section->output_section->vma); | |
659 | ||
660 | (*swap_ext_out) (abfd, &esym, | |
661 | ((char *) debug->external_ext | |
662 | + symhdr->iextMax * swap->external_ext_size)); | |
663 | ||
664 | if (set_index) | |
665 | (*set_index) (sym_ptr, symhdr->iextMax); | |
666 | ||
667 | ++symhdr->iextMax; | |
668 | ||
669 | strcpy (debug->ssext + symhdr->issExtMax, sym_ptr->name); | |
670 | symhdr->issExtMax += strlen (sym_ptr->name) + 1; | |
671 | } | |
672 | ||
673 | return true; | |
674 | } | |
675 | ||
676 | /* Align the ECOFF debugging information. */ | |
677 | ||
678 | static void | |
679 | ecoff_align_debug (abfd, debug, swap) | |
680 | bfd *abfd; | |
681 | struct ecoff_debug_info *debug; | |
682 | const struct ecoff_debug_swap *swap; | |
683 | { | |
684 | HDRR * const symhdr = &debug->symbolic_header; | |
685 | bfd_size_type debug_align, aux_align, add; | |
686 | ||
687 | /* Adjust the counts so that structures are aligned. The alignment | |
688 | of ALLOC_SIZE ensures that we do not have to worry about running | |
689 | off the end of the memory block when doing the memset. */ | |
690 | debug_align = swap->debug_align; | |
691 | aux_align = debug_align / sizeof (union aux_ext); | |
692 | ||
693 | add = debug_align - (symhdr->cbLine & (debug_align - 1)); | |
694 | if (add != debug_align) | |
695 | { | |
696 | memset (debug->line + symhdr->cbLine, 0, add); | |
697 | symhdr->cbLine += add; | |
698 | } | |
699 | ||
700 | add = debug_align - (symhdr->issMax & (debug_align - 1)); | |
701 | if (add != debug_align) | |
702 | { | |
703 | memset (debug->ss + symhdr->issMax, 0, add); | |
704 | symhdr->issMax += add; | |
705 | } | |
706 | ||
707 | add = debug_align - (symhdr->issExtMax & (debug_align - 1)); | |
708 | if (add != debug_align) | |
709 | { | |
710 | memset (debug->ssext + symhdr->issExtMax, 0, add); | |
711 | symhdr->issExtMax += add; | |
712 | } | |
713 | ||
714 | add = aux_align - (symhdr->iauxMax & (aux_align - 1)); | |
715 | if (add != aux_align) | |
716 | { | |
717 | memset (debug->external_aux + symhdr->iauxMax, 0, | |
718 | add * sizeof (union aux_ext)); | |
719 | symhdr->iauxMax += add; | |
720 | } | |
721 | } | |
722 | ||
723 | /* Return the size required by the ECOFF debugging information. */ | |
724 | ||
725 | bfd_size_type | |
726 | bfd_ecoff_debug_size (abfd, debug, swap) | |
727 | bfd *abfd; | |
728 | struct ecoff_debug_info *debug; | |
729 | const struct ecoff_debug_swap *swap; | |
730 | { | |
731 | bfd_size_type tot; | |
732 | ||
733 | ecoff_align_debug (abfd, debug, swap); | |
734 | tot = swap->external_hdr_size; | |
735 | ||
736 | #define ADD(count, size) \ | |
737 | tot += debug->symbolic_header.count * size | |
738 | ||
739 | ADD (cbLine, sizeof (unsigned char)); | |
740 | ADD (idnMax, swap->external_dnr_size); | |
741 | ADD (ipdMax, swap->external_pdr_size); | |
742 | ADD (isymMax, swap->external_sym_size); | |
743 | ADD (ioptMax, swap->external_opt_size); | |
744 | ADD (iauxMax, sizeof (union aux_ext)); | |
745 | ADD (issMax, sizeof (char)); | |
746 | ADD (issExtMax, sizeof (char)); | |
747 | ADD (ifdMax, swap->external_fdr_size); | |
748 | ADD (crfd, swap->external_rfd_size); | |
749 | ADD (iextMax, swap->external_ext_size); | |
750 | ||
751 | #undef ADD | |
752 | ||
753 | return tot; | |
754 | } | |
755 | ||
756 | /* Write out the ECOFF debugging information. This function assumes | |
757 | that the information (the pointers and counts) in *DEBUG have been | |
758 | set correctly. WHERE is the position in the file to write the | |
759 | information to. This function fills in the file offsets in the | |
760 | symbolic header. */ | |
761 | ||
762 | boolean | |
763 | bfd_ecoff_write_debug (abfd, debug, swap, where) | |
764 | bfd *abfd; | |
765 | struct ecoff_debug_info *debug; | |
766 | const struct ecoff_debug_swap *swap; | |
767 | file_ptr where; | |
768 | { | |
769 | HDRR * const symhdr = &debug->symbolic_header; | |
770 | char *buff; | |
771 | ||
772 | ecoff_align_debug (abfd, debug, swap); | |
773 | ||
774 | /* Go to the right location in the file. */ | |
775 | if (bfd_seek (abfd, where, SEEK_SET) != 0) | |
776 | return false; | |
777 | ||
778 | where += swap->external_hdr_size; | |
779 | ||
780 | /* Fill in the file offsets. */ | |
781 | #define SET(offset, count, size) \ | |
782 | if (symhdr->count == 0) \ | |
783 | symhdr->offset = 0; \ | |
784 | else \ | |
785 | { \ | |
786 | symhdr->offset = where; \ | |
787 | where += symhdr->count * size; \ | |
788 | } | |
789 | ||
790 | SET (cbLineOffset, cbLine, sizeof (unsigned char)); | |
791 | SET (cbDnOffset, idnMax, swap->external_dnr_size); | |
792 | SET (cbPdOffset, ipdMax, swap->external_pdr_size); | |
793 | SET (cbSymOffset, isymMax, swap->external_sym_size); | |
794 | SET (cbOptOffset, ioptMax, swap->external_opt_size); | |
795 | SET (cbAuxOffset, iauxMax, sizeof (union aux_ext)); | |
796 | SET (cbSsOffset, issMax, sizeof (char)); | |
797 | SET (cbSsExtOffset, issExtMax, sizeof (char)); | |
798 | SET (cbFdOffset, ifdMax, swap->external_fdr_size); | |
799 | SET (cbRfdOffset, crfd, swap->external_rfd_size); | |
800 | SET (cbExtOffset, iextMax, swap->external_ext_size); | |
801 | #undef SET | |
802 | ||
803 | buff = (PTR) alloca (swap->external_hdr_size); | |
804 | (*swap->swap_hdr_out) (abfd, symhdr, buff); | |
805 | if (bfd_write (buff, 1, swap->external_hdr_size, abfd) | |
806 | != swap->external_hdr_size) | |
807 | return false; | |
808 | ||
809 | #define WRITE(ptr, count, size, offset) \ | |
810 | BFD_ASSERT (symhdr->offset == 0 || bfd_tell (abfd) == symhdr->offset); \ | |
811 | if (bfd_write (debug->ptr, size, symhdr->count, abfd) \ | |
812 | != size * symhdr->count) \ | |
813 | return false; | |
814 | ||
815 | WRITE (line, cbLine, sizeof (unsigned char), cbLineOffset); | |
816 | WRITE (external_dnr, idnMax, swap->external_dnr_size, cbDnOffset); | |
817 | WRITE (external_pdr, ipdMax, swap->external_pdr_size, cbPdOffset); | |
818 | WRITE (external_sym, isymMax, swap->external_sym_size, cbSymOffset); | |
819 | WRITE (external_opt, ioptMax, swap->external_opt_size, cbOptOffset); | |
820 | WRITE (external_aux, iauxMax, sizeof (union aux_ext), cbAuxOffset); | |
821 | WRITE (ss, issMax, sizeof (char), cbSsOffset); | |
822 | WRITE (ssext, issExtMax, sizeof (char), cbSsExtOffset); | |
823 | WRITE (external_fdr, ifdMax, swap->external_fdr_size, cbFdOffset); | |
824 | WRITE (external_rfd, crfd, swap->external_rfd_size, cbRfdOffset); | |
825 | WRITE (external_ext, iextMax, swap->external_ext_size, cbExtOffset); | |
826 | #undef WRITE | |
827 | ||
828 | return true; | |
829 | } |