Commit | Line | Data |
---|---|---|
0c376465 | 1 | /* vms-misc.c -- BFD back-end for VMS/VAX (openVMS/VAX) and |
252b5132 | 2 | EVAX (openVMS/Alpha) files. |
3db64b00 | 3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, |
0c376465 TG |
4 | 2007, 2008, 2009 Free Software Foundation, Inc. |
5 | ||
6 | Miscellaneous functions. | |
252b5132 RH |
7 | |
8 | Written by Klaus K"ampf (kkaempf@rmi.de) | |
9 | ||
7920ce38 NC |
10 | This program is free software; you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License as published by | |
cd123cb7 | 12 | the Free Software Foundation; either version 3 of the License, or |
7920ce38 | 13 | (at your option) any later version. |
252b5132 | 14 | |
7920ce38 NC |
15 | This program is distributed in the hope that it will be useful, |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | GNU General Public License for more details. | |
252b5132 | 19 | |
7920ce38 NC |
20 | You should have received a copy of the GNU General Public License |
21 | along with this program; if not, write to the Free Software | |
cd123cb7 NC |
22 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
23 | MA 02110-1301, USA. */ | |
252b5132 | 24 | |
252b5132 RH |
25 | #if __STDC__ |
26 | #include <stdarg.h> | |
27 | #endif | |
28 | ||
252b5132 | 29 | #include "sysdep.h" |
3db64b00 | 30 | #include "bfd.h" |
252b5132 RH |
31 | #include "bfdlink.h" |
32 | #include "libbfd.h" | |
4b544b64 | 33 | #include "safe-ctype.h" |
252b5132 RH |
34 | |
35 | #include "vms.h" | |
0c376465 TG |
36 | |
37 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) | |
38 | ||
39 | static int hash_string PARAMS ((const char *)); | |
40 | static asymbol *new_symbol PARAMS ((bfd *, char *)); | |
41 | static void maybe_adjust_record_pointer_for_object PARAMS ((bfd *)); | |
42 | static int vms_get_remaining_object_record PARAMS ((bfd *, int )); | |
43 | static int vms_get_remaining_image_record PARAMS ((bfd *, int )); | |
44 | ||
252b5132 | 45 | #if VMS_DEBUG |
7920ce38 | 46 | /* Debug functions. */ |
252b5132 | 47 | |
0c376465 TG |
48 | /* Debug function for all vms extensions evaluates environment |
49 | variable VMS_DEBUG for a numerical value on the first call all | |
50 | error levels below this value are printed: | |
558e161f | 51 | |
0c376465 | 52 | Levels: |
252b5132 RH |
53 | 1 toplevel bfd calls (functions from the bfd vector) |
54 | 2 functions called by bfd calls | |
55 | ... | |
56 | 9 almost everything | |
57 | ||
0c376465 | 58 | Level is also indentation level. Indentation is performed |
7920ce38 | 59 | if level > 0. */ |
252b5132 | 60 | |
252b5132 RH |
61 | void |
62 | _bfd_vms_debug (int level, char *format, ...) | |
63 | { | |
64 | static int min_level = -1; | |
65 | static FILE *output = NULL; | |
66 | char *eptr; | |
67 | va_list args; | |
7920ce38 | 68 | int abslvl = (level > 0) ? level : - level; |
252b5132 RH |
69 | |
70 | if (min_level == -1) | |
71 | { | |
7920ce38 | 72 | if ((eptr = getenv ("VMS_DEBUG")) != NULL) |
252b5132 | 73 | { |
7920ce38 | 74 | min_level = atoi (eptr); |
252b5132 RH |
75 | output = stderr; |
76 | } | |
77 | else | |
78 | min_level = 0; | |
79 | } | |
80 | if (output == NULL) | |
81 | return; | |
82 | if (abslvl > min_level) | |
83 | return; | |
84 | ||
558e161f KH |
85 | while (--level>0) |
86 | fprintf (output, " "); | |
7920ce38 | 87 | va_start (args, format); |
558e161f | 88 | vfprintf (output, format, args); |
7920ce38 NC |
89 | fflush (output); |
90 | va_end (args); | |
252b5132 RH |
91 | } |
92 | ||
7920ce38 NC |
93 | /* A debug function |
94 | hex dump 'size' bytes starting at 'ptr'. */ | |
252b5132 RH |
95 | |
96 | void | |
7920ce38 NC |
97 | _bfd_hexdump (int level, |
98 | unsigned char *ptr, | |
99 | int size, | |
100 | int offset) | |
252b5132 RH |
101 | { |
102 | unsigned char *lptr = ptr; | |
103 | int count = 0; | |
104 | long start = offset; | |
105 | ||
106 | while (size-- > 0) | |
107 | { | |
108 | if ((count%16) == 0) | |
109 | vms_debug (level, "%08lx:", start); | |
110 | vms_debug (-level, " %02x", *ptr++); | |
111 | count++; | |
112 | start++; | |
113 | if (size == 0) | |
114 | { | |
115 | while ((count%16) != 0) | |
116 | { | |
117 | vms_debug (-level, " "); | |
118 | count++; | |
119 | } | |
120 | } | |
121 | if ((count%16) == 0) | |
122 | { | |
123 | vms_debug (-level, " "); | |
124 | while (lptr < ptr) | |
125 | { | |
126 | vms_debug (-level, "%c", (*lptr < 32)?'.':*lptr); | |
127 | lptr++; | |
128 | } | |
129 | vms_debug (-level, "\n"); | |
130 | } | |
131 | } | |
132 | if ((count%16) != 0) | |
133 | vms_debug (-level, "\n"); | |
252b5132 RH |
134 | } |
135 | #endif | |
252b5132 | 136 | \f |
7920ce38 | 137 | /* Hash functions |
252b5132 RH |
138 | |
139 | These are needed when reading an object file. */ | |
140 | ||
7920ce38 NC |
141 | /* Allocate new vms_hash_entry |
142 | keep the symbol name and a pointer to the bfd symbol in the table. */ | |
252b5132 RH |
143 | |
144 | struct bfd_hash_entry * | |
7920ce38 NC |
145 | _bfd_vms_hash_newfunc (struct bfd_hash_entry *entry, |
146 | struct bfd_hash_table *table, | |
147 | const char *string) | |
252b5132 RH |
148 | { |
149 | vms_symbol_entry *ret; | |
150 | ||
151 | #if VMS_DEBUG | |
7920ce38 | 152 | vms_debug (5, "_bfd_vms_hash_newfunc (%p, %p, %s)\n", entry, table, string); |
252b5132 RH |
153 | #endif |
154 | ||
7920ce38 | 155 | if (entry == NULL) |
252b5132 RH |
156 | { |
157 | ret = (vms_symbol_entry *) | |
158 | bfd_hash_allocate (table, sizeof (vms_symbol_entry)); | |
7920ce38 | 159 | if (ret == NULL) |
252b5132 RH |
160 | { |
161 | bfd_set_error (bfd_error_no_memory); | |
7920ce38 | 162 | return NULL; |
252b5132 | 163 | } |
015985c9 | 164 | entry = (struct bfd_hash_entry *) ret; |
252b5132 RH |
165 | } |
166 | ||
167 | /* Call the allocation method of the base class. */ | |
015985c9 | 168 | ret = (vms_symbol_entry *) bfd_hash_newfunc (entry, table, string); |
252b5132 RH |
169 | #if VMS_DEBUG |
170 | vms_debug (6, "_bfd_vms_hash_newfunc ret %p\n", ret); | |
171 | #endif | |
172 | ||
7920ce38 | 173 | ret->symbol = NULL; |
252b5132 RH |
174 | |
175 | return (struct bfd_hash_entry *)ret; | |
176 | } | |
252b5132 | 177 | \f |
7920ce38 | 178 | /* Object file input functions. */ |
252b5132 | 179 | |
0c376465 | 180 | /* Return type and size from record header (buf) on Alpha. */ |
252b5132 RH |
181 | |
182 | void | |
7920ce38 NC |
183 | _bfd_vms_get_header_values (bfd * abfd ATTRIBUTE_UNUSED, |
184 | unsigned char *buf, | |
185 | int *type, | |
0c376465 | 186 | int *size) |
252b5132 | 187 | { |
0c376465 | 188 | if (type) |
252b5132 | 189 | *type = bfd_getl16 (buf); |
0c376465 TG |
190 | |
191 | if (size) | |
192 | *size = bfd_getl16 (buf+2); | |
252b5132 RH |
193 | |
194 | #if VMS_DEBUG | |
0c376465 TG |
195 | vms_debug (10, "_bfd_vms_get_header_values type %x, size %x\n", |
196 | type ? *type : 0, size ? *size : 0); | |
252b5132 | 197 | #endif |
252b5132 RH |
198 | } |
199 | ||
7920ce38 NC |
200 | /* Get next record from object file to vms_buf. |
201 | Set PRIV(buf_size) and return it | |
558e161f | 202 | |
7920ce38 | 203 | This is a little tricky since it should be portable. |
558e161f | 204 | |
7920ce38 | 205 | The openVMS object file has 'variable length' which means that |
252b5132 | 206 | read() returns data in chunks of (hopefully) correct and expected |
0c376465 TG |
207 | size. The linker (and other tools on VMS) depend on that. Unix |
208 | doesn't know about 'formatted' files, so reading and writing such | |
209 | an object file in a Unix environment is not trivial. | |
558e161f | 210 | |
0c376465 TG |
211 | With the tool 'file' (available on all VMS FTP sites), one |
212 | can view and change the attributes of a file. Changing from | |
252b5132 | 213 | 'variable length' to 'fixed length, 512 bytes' reveals the |
0c376465 | 214 | record size at the first 2 bytes of every record. The same |
771deb08 | 215 | may happen during the transfer of object files from VMS to Unix, |
0c376465 | 216 | at least with UCX, the DEC implementation of TCP/IP. |
558e161f | 217 | |
0c376465 | 218 | The VMS format repeats the size at bytes 2 & 3 of every record. |
558e161f | 219 | |
252b5132 RH |
220 | On the first call (file_format == FF_UNKNOWN) we check if |
221 | the first and the third byte pair (!) of the record match. | |
0c376465 TG |
222 | If they do it's an object file in an Unix environment or with |
223 | wrong attributes (FF_FOREIGN), else we should be in a VMS | |
252b5132 | 224 | environment where read() returns the record size (FF_NATIVE). |
558e161f | 225 | |
0c376465 TG |
226 | Reading is always done in 2 steps: |
227 | 1. first just the record header is read and the size extracted, | |
228 | 2. then the read buffer is adjusted and the remaining bytes are | |
229 | read in. | |
230 | ||
231 | All file I/O is done on even file positions. */ | |
558e161f | 232 | |
0c376465 TG |
233 | #define VMS_OBJECT_ADJUSTMENT 2 |
234 | ||
235 | static void | |
236 | maybe_adjust_record_pointer_for_object (bfd *abfd) | |
237 | { | |
238 | /* Set the file format once for all on the first invocation. */ | |
239 | if (PRIV (file_format) == FF_UNKNOWN) | |
240 | { | |
241 | if (PRIV (vms_rec)[0] == PRIV (vms_rec)[4] | |
242 | && PRIV (vms_rec)[1] == PRIV (vms_rec)[5]) | |
243 | PRIV (file_format) = FF_FOREIGN; | |
244 | else | |
245 | PRIV (file_format) = FF_NATIVE; | |
246 | } | |
247 | ||
248 | /* The adjustment is needed only in an Unix environment. */ | |
249 | if (PRIV (file_format) == FF_FOREIGN) | |
250 | PRIV (vms_rec) += VMS_OBJECT_ADJUSTMENT; | |
251 | } | |
252 | ||
253 | /* Get first record from file and return the file type. */ | |
252b5132 RH |
254 | |
255 | int | |
0c376465 | 256 | _bfd_vms_get_first_record (bfd *abfd) |
252b5132 | 257 | { |
0c376465 | 258 | unsigned int test_len; |
252b5132 RH |
259 | |
260 | #if VMS_DEBUG | |
0c376465 | 261 | vms_debug (8, "_bfd_vms_get_first_record\n"); |
252b5132 RH |
262 | #endif |
263 | ||
0c376465 TG |
264 | if (PRIV (is_vax)) |
265 | test_len = 0; | |
266 | else | |
267 | /* Minimum is 6 bytes for objects (2 bytes size, 2 bytes record id, | |
268 | 2 bytes size repeated) and 12 bytes for images (4 bytes major id, | |
269 | 4 bytes minor id, 4 bytes length). */ | |
270 | test_len = 12; | |
252b5132 | 271 | |
0c376465 | 272 | /* Size the main buffer. */ |
47eee8a9 | 273 | if (PRIV (buf_size) == 0) |
252b5132 | 274 | { |
0c376465 TG |
275 | /* On VAX there's no size information in the record, so |
276 | start with OBJ_S_C_MAXRECSIZ. */ | |
277 | bfd_size_type amt = (test_len ? test_len : OBJ_S_C_MAXRECSIZ); | |
278 | PRIV (vms_buf) = (unsigned char *) bfd_malloc (amt); | |
487e54f2 | 279 | PRIV (buf_size) = amt; |
252b5132 RH |
280 | } |
281 | ||
0c376465 TG |
282 | /* Initialize the record pointer. */ |
283 | PRIV (vms_rec) = PRIV (vms_buf); | |
252b5132 | 284 | |
0c376465 TG |
285 | /* We only support modules on VAX. */ |
286 | if (PRIV (is_vax)) | |
252b5132 | 287 | { |
0c376465 TG |
288 | if (vms_get_remaining_object_record (abfd, test_len) <= 0) |
289 | return FT_UNKNOWN; | |
290 | ||
291 | #if VMS_DEBUG | |
292 | vms_debug (2, "file type is VAX module\n"); | |
293 | #endif | |
294 | ||
295 | return FT_MODULE; | |
02b89dce | 296 | } |
252b5132 | 297 | |
0c376465 TG |
298 | if (bfd_bread (PRIV (vms_buf), test_len, abfd) != test_len) |
299 | { | |
300 | bfd_set_error (bfd_error_file_truncated); | |
301 | return FT_UNKNOWN; | |
302 | } | |
252b5132 | 303 | |
0c376465 TG |
304 | /* Is it an image? */ |
305 | if ((bfd_getl32 (PRIV (vms_rec)) == EIHD_S_K_MAJORID) | |
306 | && (bfd_getl32 (PRIV (vms_rec) + 4) == EIHD_S_K_MINORID)) | |
252b5132 | 307 | { |
0c376465 TG |
308 | if (vms_get_remaining_image_record (abfd, test_len) <= 0) |
309 | return FT_UNKNOWN; | |
310 | ||
311 | #if VMS_DEBUG | |
312 | vms_debug (2, "file type is image\n"); | |
313 | #endif | |
314 | ||
315 | return FT_IMAGE; | |
252b5132 RH |
316 | } |
317 | ||
0c376465 TG |
318 | /* Assume it's a module and adjust record pointer if necessary. */ |
319 | maybe_adjust_record_pointer_for_object (abfd); | |
320 | ||
321 | /* But is it really a module? */ | |
322 | if (bfd_getl16 (PRIV (vms_rec)) <= EOBJ_S_C_MAXRECTYP | |
323 | && bfd_getl16 (PRIV (vms_rec) + 2) <= EOBJ_S_C_MAXRECSIZ) | |
252b5132 | 324 | { |
0c376465 TG |
325 | if (vms_get_remaining_object_record (abfd, test_len) <= 0) |
326 | return FT_UNKNOWN; | |
327 | ||
328 | #if VMS_DEBUG | |
329 | vms_debug (2, "file type is module\n"); | |
330 | #endif | |
331 | ||
332 | return FT_MODULE; | |
252b5132 RH |
333 | } |
334 | ||
0c376465 TG |
335 | #if VMS_DEBUG |
336 | vms_debug (2, "file type is unknown\n"); | |
337 | #endif | |
338 | ||
339 | return FT_UNKNOWN; | |
340 | } | |
341 | ||
342 | /* Implement step #1 of the object record reading procedure. | |
343 | Return the record type or -1 on failure. */ | |
344 | ||
345 | int | |
346 | _bfd_vms_get_object_record (bfd *abfd) | |
347 | { | |
348 | unsigned int test_len; | |
349 | int type; | |
350 | ||
351 | #if VMS_DEBUG | |
352 | vms_debug (8, "_bfd_vms_get_obj_record\n"); | |
353 | #endif | |
354 | ||
355 | if (PRIV (is_vax)) | |
356 | test_len = 0; | |
357 | else | |
358 | { | |
771deb08 TG |
359 | int off = 0; |
360 | ||
0c376465 TG |
361 | /* See _bfd_vms_get_first_record. */ |
362 | test_len = 6; | |
363 | ||
364 | /* Skip odd alignment byte. */ | |
365 | if (bfd_tell (abfd) & 1) | |
252b5132 | 366 | { |
0c376465 TG |
367 | if (bfd_bread (PRIV (vms_buf), 1, abfd) != 1) |
368 | { | |
369 | bfd_set_error (bfd_error_file_truncated); | |
370 | return -1; | |
371 | } | |
771deb08 TG |
372 | /* Alignment byte may be present or not. This is not easy to |
373 | detect but all object record types are not 0 (on Alpha VMS). | |
374 | We also hope that pad byte is 0. */ | |
375 | if (PRIV (vms_buf)[0]) | |
376 | off = 1; | |
252b5132 | 377 | } |
0c376465 TG |
378 | |
379 | /* Read the record header */ | |
771deb08 TG |
380 | if (bfd_bread (PRIV (vms_buf) + off, test_len - off, abfd) |
381 | != test_len - off) | |
252b5132 | 382 | { |
0c376465 TG |
383 | bfd_set_error (bfd_error_file_truncated); |
384 | return -1; | |
252b5132 | 385 | } |
0c376465 TG |
386 | |
387 | /* Reset the record pointer. */ | |
388 | PRIV (vms_rec) = PRIV (vms_buf); | |
389 | maybe_adjust_record_pointer_for_object (abfd); | |
252b5132 RH |
390 | } |
391 | ||
0c376465 TG |
392 | if (vms_get_remaining_object_record (abfd, test_len) <= 0) |
393 | return -1; | |
394 | ||
395 | if (PRIV (is_vax)) | |
396 | type = PRIV (vms_rec) [0]; | |
397 | else | |
398 | type = bfd_getl16 (PRIV (vms_rec)); | |
399 | ||
400 | #if VMS_DEBUG | |
401 | vms_debug (8, "_bfd_vms_get_obj_record: rec %p, size %d, type %d\n", | |
402 | PRIV (vms_rec), PRIV (rec_size), type); | |
403 | #endif | |
404 | ||
405 | return type; | |
406 | } | |
407 | ||
408 | /* Implement step #2 of the object record reading procedure. | |
409 | Return the size of the record or 0 on failure. */ | |
410 | ||
411 | static int | |
412 | vms_get_remaining_object_record (bfd *abfd, int read_so_far) | |
413 | { | |
414 | #if VMS_DEBUG | |
415 | vms_debug (8, "vms_get_remaining_obj_record\n"); | |
416 | #endif | |
417 | ||
47eee8a9 | 418 | if (PRIV (is_vax)) |
252b5132 | 419 | { |
0c376465 TG |
420 | if (read_so_far != 0) |
421 | abort (); | |
422 | ||
423 | PRIV (rec_size) = bfd_bread (PRIV (vms_buf), PRIV (buf_size), abfd); | |
424 | ||
425 | if (PRIV (rec_size) <= 0) | |
252b5132 RH |
426 | { |
427 | bfd_set_error (bfd_error_file_truncated); | |
428 | return 0; | |
429 | } | |
0c376465 TG |
430 | |
431 | /* Reset the record pointer. */ | |
432 | PRIV (vms_rec) = PRIV (vms_buf); | |
252b5132 | 433 | } |
7920ce38 | 434 | else |
252b5132 | 435 | { |
0c376465 | 436 | unsigned int to_read; |
252b5132 | 437 | |
0c376465 TG |
438 | /* Extract record size. */ |
439 | PRIV (rec_size) = bfd_getl16 (PRIV (vms_rec) + 2); | |
252b5132 | 440 | |
0c376465 | 441 | if (PRIV (rec_size) <= 0) |
252b5132 RH |
442 | { |
443 | bfd_set_error (bfd_error_file_truncated); | |
444 | return 0; | |
445 | } | |
446 | ||
7920ce38 | 447 | /* That's what the linker manual says. */ |
0c376465 | 448 | if (PRIV (rec_size) > EOBJ_S_C_MAXRECSIZ) |
252b5132 RH |
449 | { |
450 | bfd_set_error (bfd_error_file_truncated); | |
451 | return 0; | |
452 | } | |
453 | ||
0c376465 TG |
454 | /* Take into account object adjustment. */ |
455 | to_read = PRIV (rec_size); | |
456 | if (PRIV (file_format) == FF_FOREIGN) | |
457 | to_read += VMS_OBJECT_ADJUSTMENT; | |
252b5132 | 458 | |
0c376465 TG |
459 | /* Adjust the buffer. */ |
460 | if (to_read > PRIV (buf_size)) | |
252b5132 | 461 | { |
0c376465 TG |
462 | PRIV (vms_buf) |
463 | = (unsigned char *) bfd_realloc (PRIV (vms_buf), to_read); | |
464 | if (PRIV (vms_buf) == NULL) | |
465 | return 0; | |
466 | PRIV (buf_size) = to_read; | |
252b5132 RH |
467 | } |
468 | ||
7920ce38 | 469 | /* Read the remaining record. */ |
0c376465 | 470 | to_read -= read_so_far; |
252b5132 RH |
471 | |
472 | #if VMS_DEBUG | |
0c376465 | 473 | vms_debug (8, "vms_get_remaining_obj_record: to_read %d\n", to_read); |
252b5132 | 474 | #endif |
0c376465 TG |
475 | |
476 | if (bfd_bread (PRIV (vms_buf) + read_so_far, to_read, abfd) != to_read) | |
252b5132 RH |
477 | { |
478 | bfd_set_error (bfd_error_file_truncated); | |
479 | return 0; | |
480 | } | |
0c376465 TG |
481 | |
482 | /* Reset the record pointer. */ | |
483 | PRIV (vms_rec) = PRIV (vms_buf); | |
484 | maybe_adjust_record_pointer_for_object (abfd); | |
252b5132 RH |
485 | } |
486 | ||
487 | #if VMS_DEBUG | |
0c376465 | 488 | vms_debug (8, "vms_get_remaining_obj_record: size %d\n", PRIV (rec_size)); |
252b5132 RH |
489 | #endif |
490 | ||
0c376465 | 491 | return PRIV (rec_size); |
252b5132 RH |
492 | } |
493 | ||
0c376465 TG |
494 | /* Implement step #2 of the record reading procedure for images. |
495 | Return the size of the record or 0 on failure. */ | |
252b5132 | 496 | |
0c376465 TG |
497 | static int |
498 | vms_get_remaining_image_record (bfd *abfd, int read_so_far) | |
252b5132 | 499 | { |
0c376465 TG |
500 | unsigned int to_read; |
501 | int remaining; | |
252b5132 | 502 | |
0c376465 TG |
503 | /* Extract record size. */ |
504 | PRIV (rec_size) = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_SIZE); | |
505 | ||
506 | if (PRIV (rec_size) > PRIV (buf_size)) | |
252b5132 | 507 | { |
0c376465 TG |
508 | PRIV (vms_buf) = bfd_realloc (PRIV (vms_buf), PRIV (rec_size)); |
509 | ||
510 | if (PRIV (vms_buf) == NULL) | |
511 | { | |
512 | bfd_set_error (bfd_error_no_memory); | |
513 | return 0; | |
514 | } | |
515 | ||
516 | PRIV (buf_size) = PRIV (rec_size); | |
252b5132 RH |
517 | } |
518 | ||
0c376465 TG |
519 | /* Read the remaining record. */ |
520 | remaining = PRIV (rec_size) - read_so_far; | |
521 | to_read = MIN (VMS_BLOCK_SIZE - read_so_far, remaining); | |
63e39178 | 522 | |
0c376465 | 523 | while (remaining > 0) |
252b5132 | 524 | { |
0c376465 TG |
525 | if (bfd_bread (PRIV (vms_buf) + read_so_far, to_read, abfd) != to_read) |
526 | { | |
527 | bfd_set_error (bfd_error_file_truncated); | |
528 | return 0; | |
529 | } | |
7920ce38 | 530 | |
0c376465 TG |
531 | read_so_far += to_read; |
532 | remaining -= to_read; | |
252b5132 | 533 | |
0c376465 TG |
534 | /* Eat trailing 0xff's. */ |
535 | if (remaining > 0) | |
536 | while (PRIV (vms_buf) [read_so_far - 1] == 0xff) | |
537 | read_so_far--; | |
538 | ||
539 | to_read = MIN (VMS_BLOCK_SIZE, remaining); | |
540 | } | |
252b5132 | 541 | |
0c376465 TG |
542 | /* Reset the record pointer. */ |
543 | PRIV (vms_rec) = PRIV (vms_buf); | |
544 | ||
545 | return PRIV (rec_size); | |
252b5132 | 546 | } |
0c376465 TG |
547 | |
548 | /* Copy sized string (string with fixed size) to new allocated area | |
549 | size is string size (size of record) */ | |
252b5132 RH |
550 | |
551 | char * | |
7920ce38 | 552 | _bfd_vms_save_sized_string (unsigned char *str, int size) |
252b5132 | 553 | { |
dc810e39 | 554 | char *newstr = bfd_malloc ((bfd_size_type) size + 1); |
252b5132 RH |
555 | |
556 | if (newstr == NULL) | |
7920ce38 | 557 | return NULL; |
dc810e39 | 558 | strncpy (newstr, (char *) str, (size_t) size); |
252b5132 RH |
559 | newstr[size] = 0; |
560 | ||
561 | return newstr; | |
562 | } | |
563 | ||
0c376465 TG |
564 | /* Copy counted string (string with size at first byte) to new allocated area |
565 | ptr points to size byte on entry */ | |
252b5132 RH |
566 | |
567 | char * | |
7920ce38 | 568 | _bfd_vms_save_counted_string (unsigned char *ptr) |
252b5132 RH |
569 | { |
570 | int len = *ptr++; | |
571 | ||
572 | return _bfd_vms_save_sized_string (ptr, len); | |
573 | } | |
252b5132 | 574 | \f |
7920ce38 | 575 | /* Stack routines for vms ETIR commands. */ |
252b5132 | 576 | |
7920ce38 | 577 | /* Push value and section index. */ |
252b5132 RH |
578 | |
579 | void | |
7920ce38 | 580 | _bfd_vms_push (bfd * abfd, uquad val, int psect) |
252b5132 RH |
581 | { |
582 | static int last_psect; | |
583 | ||
584 | #if VMS_DEBUG | |
7920ce38 | 585 | vms_debug (4, "<push %016lx (%d) at %d>\n", val, psect, PRIV (stackptr)); |
252b5132 RH |
586 | #endif |
587 | ||
588 | if (psect >= 0) | |
589 | last_psect = psect; | |
590 | ||
47eee8a9 KH |
591 | PRIV (stack[PRIV (stackptr)]).value = val; |
592 | PRIV (stack[PRIV (stackptr)]).psect = last_psect; | |
593 | PRIV (stackptr)++; | |
594 | if (PRIV (stackptr) >= STACKSIZE) | |
252b5132 RH |
595 | { |
596 | bfd_set_error (bfd_error_bad_value); | |
47eee8a9 | 597 | (*_bfd_error_handler) (_("Stack overflow (%d) in _bfd_vms_push"), PRIV (stackptr)); |
252b5132 RH |
598 | exit (1); |
599 | } | |
252b5132 RH |
600 | } |
601 | ||
7920ce38 | 602 | /* Pop value and section index. */ |
252b5132 RH |
603 | |
604 | uquad | |
7920ce38 | 605 | _bfd_vms_pop (bfd * abfd, int *psect) |
252b5132 RH |
606 | { |
607 | uquad value; | |
608 | ||
47eee8a9 | 609 | if (PRIV (stackptr) == 0) |
252b5132 RH |
610 | { |
611 | bfd_set_error (bfd_error_bad_value); | |
612 | (*_bfd_error_handler) (_("Stack underflow in _bfd_vms_pop")); | |
613 | exit (1); | |
614 | } | |
47eee8a9 KH |
615 | PRIV (stackptr)--; |
616 | value = PRIV (stack[PRIV (stackptr)]).value; | |
617 | if ((psect != NULL) && (PRIV (stack[PRIV (stackptr)]).psect >= 0)) | |
618 | *psect = PRIV (stack[PRIV (stackptr)]).psect; | |
252b5132 RH |
619 | |
620 | #if VMS_DEBUG | |
47eee8a9 | 621 | vms_debug (4, "<pop %016lx(%d)>\n", value, PRIV (stack[PRIV (stackptr)]).psect); |
252b5132 RH |
622 | #endif |
623 | ||
624 | return value; | |
625 | } | |
252b5132 | 626 | \f |
7920ce38 | 627 | /* Object output routines. */ |
252b5132 RH |
628 | |
629 | /* Begin new record or record header | |
630 | write 2 bytes rectype | |
631 | write 2 bytes record length (filled in at flush) | |
0c376465 | 632 | write 2 bytes header type (ommitted if rechead == -1). */ |
252b5132 RH |
633 | |
634 | void | |
7920ce38 | 635 | _bfd_vms_output_begin (bfd * abfd, int rectype, int rechead) |
252b5132 RH |
636 | { |
637 | #if VMS_DEBUG | |
7920ce38 | 638 | vms_debug (6, "_bfd_vms_output_begin (type %d, head %d)\n", rectype, |
252b5132 RH |
639 | rechead); |
640 | #endif | |
641 | ||
dc810e39 | 642 | _bfd_vms_output_short (abfd, (unsigned int) rectype); |
252b5132 | 643 | |
7920ce38 | 644 | /* Save current output position to fill in length later. */ |
252b5132 | 645 | |
47eee8a9 KH |
646 | if (PRIV (push_level) > 0) |
647 | PRIV (length_pos) = PRIV (output_size); | |
252b5132 RH |
648 | |
649 | #if VMS_DEBUG | |
650 | vms_debug (6, "_bfd_vms_output_begin: length_pos = %d\n", | |
47eee8a9 | 651 | PRIV (length_pos)); |
252b5132 RH |
652 | #endif |
653 | ||
7920ce38 NC |
654 | /* Placeholder for length. */ |
655 | _bfd_vms_output_short (abfd, 0); | |
252b5132 RH |
656 | |
657 | if (rechead != -1) | |
dc810e39 | 658 | _bfd_vms_output_short (abfd, (unsigned int) rechead); |
252b5132 RH |
659 | } |
660 | ||
7920ce38 | 661 | /* Set record/subrecord alignment. */ |
252b5132 RH |
662 | |
663 | void | |
7920ce38 | 664 | _bfd_vms_output_alignment (bfd * abfd, int alignto) |
252b5132 RH |
665 | { |
666 | #if VMS_DEBUG | |
7920ce38 | 667 | vms_debug (6, "_bfd_vms_output_alignment (%d)\n", alignto); |
252b5132 RH |
668 | #endif |
669 | ||
47eee8a9 | 670 | PRIV (output_alignment) = alignto; |
252b5132 RH |
671 | } |
672 | ||
7920ce38 | 673 | /* Prepare for subrecord fields. */ |
252b5132 RH |
674 | |
675 | void | |
7920ce38 | 676 | _bfd_vms_output_push (bfd * abfd) |
252b5132 RH |
677 | { |
678 | #if VMS_DEBUG | |
7920ce38 | 679 | vms_debug (6, "vms_output_push (pushed_size = %d)\n", PRIV (output_size)); |
252b5132 RH |
680 | #endif |
681 | ||
47eee8a9 KH |
682 | PRIV (push_level)++; |
683 | PRIV (pushed_size) = PRIV (output_size); | |
252b5132 RH |
684 | } |
685 | ||
7920ce38 | 686 | /* End of subrecord fields. */ |
252b5132 RH |
687 | |
688 | void | |
7920ce38 | 689 | _bfd_vms_output_pop (bfd * abfd) |
252b5132 RH |
690 | { |
691 | #if VMS_DEBUG | |
7920ce38 | 692 | vms_debug (6, "vms_output_pop (pushed_size = %d)\n", PRIV (pushed_size)); |
252b5132 RH |
693 | #endif |
694 | ||
695 | _bfd_vms_output_flush (abfd); | |
47eee8a9 | 696 | PRIV (length_pos) = 2; |
252b5132 RH |
697 | |
698 | #if VMS_DEBUG | |
47eee8a9 | 699 | vms_debug (6, "vms_output_pop: length_pos = %d\n", PRIV (length_pos)); |
252b5132 RH |
700 | #endif |
701 | ||
47eee8a9 KH |
702 | PRIV (pushed_size) = 0; |
703 | PRIV (push_level)--; | |
252b5132 RH |
704 | } |
705 | ||
7920ce38 | 706 | /* Flush unwritten output, ends current record. */ |
252b5132 RH |
707 | |
708 | void | |
7920ce38 | 709 | _bfd_vms_output_flush (bfd * abfd) |
252b5132 | 710 | { |
47eee8a9 | 711 | int real_size = PRIV (output_size); |
252b5132 RH |
712 | int aligncount; |
713 | int length; | |
714 | ||
715 | #if VMS_DEBUG | |
7920ce38 | 716 | vms_debug (6, "_bfd_vms_output_flush (real_size = %d, pushed_size %d at lenpos %d)\n", |
47eee8a9 | 717 | real_size, PRIV (pushed_size), PRIV (length_pos)); |
252b5132 RH |
718 | #endif |
719 | ||
47eee8a9 KH |
720 | if (PRIV (push_level) > 0) |
721 | length = real_size - PRIV (pushed_size); | |
252b5132 RH |
722 | else |
723 | length = real_size; | |
724 | ||
725 | if (length == 0) | |
726 | return; | |
47eee8a9 KH |
727 | aligncount = (PRIV (output_alignment) |
728 | - (length % PRIV (output_alignment))) % PRIV (output_alignment); | |
252b5132 RH |
729 | |
730 | #if VMS_DEBUG | |
731 | vms_debug (6, "align: adding %d bytes\n", aligncount); | |
732 | #endif | |
733 | ||
558e161f | 734 | while (aligncount-- > 0) |
252b5132 | 735 | { |
47eee8a9 | 736 | PRIV (output_buf)[real_size++] = 0; |
0e71e495 | 737 | length++; |
252b5132 RH |
738 | } |
739 | ||
7920ce38 | 740 | /* Put length to buffer. */ |
47eee8a9 | 741 | PRIV (output_size) = PRIV (length_pos); |
dc810e39 | 742 | _bfd_vms_output_short (abfd, (unsigned int) length); |
252b5132 | 743 | |
47eee8a9 | 744 | if (PRIV (push_level) == 0) |
252b5132 | 745 | { |
0c376465 TG |
746 | /* File is open in undefined (UDF) format on VMS, but ultimately will be |
747 | converted to variable length (VAR) format. VAR format has a length | |
748 | word first which must be explicitly output in UDF format. */ | |
749 | bfd_bwrite (PRIV (output_buf) + 2, 2, abfd); | |
750 | bfd_bwrite (PRIV (output_buf), (size_t) real_size, abfd); | |
47eee8a9 | 751 | PRIV (output_size) = 0; |
252b5132 RH |
752 | } |
753 | else | |
754 | { | |
47eee8a9 KH |
755 | PRIV (output_size) = real_size; |
756 | PRIV (pushed_size) = PRIV (output_size); | |
252b5132 | 757 | } |
252b5132 RH |
758 | } |
759 | ||
7920ce38 | 760 | /* End record output. */ |
252b5132 RH |
761 | |
762 | void | |
7920ce38 | 763 | _bfd_vms_output_end (bfd * abfd) |
252b5132 RH |
764 | { |
765 | #if VMS_DEBUG | |
766 | vms_debug (6, "_bfd_vms_output_end\n"); | |
767 | #endif | |
768 | ||
769 | _bfd_vms_output_flush (abfd); | |
252b5132 RH |
770 | } |
771 | ||
7920ce38 | 772 | /* Check remaining buffer size |
252b5132 | 773 | |
7920ce38 | 774 | Return what's left. */ |
252b5132 RH |
775 | |
776 | int | |
7920ce38 | 777 | _bfd_vms_output_check (bfd * abfd, int size) |
252b5132 RH |
778 | { |
779 | #if VMS_DEBUG | |
7920ce38 | 780 | vms_debug (6, "_bfd_vms_output_check (%d)\n", size); |
252b5132 RH |
781 | #endif |
782 | ||
47eee8a9 | 783 | return (MAX_OUTREC_SIZE - (PRIV (output_size) + size + MIN_OUTREC_LUFT)); |
252b5132 RH |
784 | } |
785 | ||
7920ce38 | 786 | /* Output byte (8 bit) value. */ |
252b5132 RH |
787 | |
788 | void | |
7920ce38 | 789 | _bfd_vms_output_byte (bfd * abfd, unsigned int value) |
252b5132 RH |
790 | { |
791 | #if VMS_DEBUG | |
7920ce38 | 792 | vms_debug (6, "_bfd_vms_output_byte (%02x)\n", value); |
252b5132 RH |
793 | #endif |
794 | ||
47eee8a9 KH |
795 | bfd_put_8 (abfd, value & 0xff, PRIV (output_buf) + PRIV (output_size)); |
796 | PRIV (output_size) += 1; | |
252b5132 RH |
797 | } |
798 | ||
7920ce38 | 799 | /* Output short (16 bit) value. */ |
252b5132 RH |
800 | |
801 | void | |
7920ce38 | 802 | _bfd_vms_output_short (bfd * abfd, unsigned int value) |
252b5132 RH |
803 | { |
804 | #if VMS_DEBUG | |
805 | vms_debug (6, "_bfd_vms_output_short (%04x)\n", value); | |
806 | #endif | |
807 | ||
dc810e39 AM |
808 | bfd_put_16 (abfd, (bfd_vma) value & 0xffff, |
809 | PRIV (output_buf) + PRIV (output_size)); | |
47eee8a9 | 810 | PRIV (output_size) += 2; |
252b5132 RH |
811 | } |
812 | ||
7920ce38 | 813 | /* Output long (32 bit) value. */ |
252b5132 RH |
814 | |
815 | void | |
7920ce38 | 816 | _bfd_vms_output_long (bfd * abfd, unsigned long value) |
252b5132 RH |
817 | { |
818 | #if VMS_DEBUG | |
819 | vms_debug (6, "_bfd_vms_output_long (%08lx)\n", value); | |
820 | #endif | |
821 | ||
dc810e39 | 822 | bfd_put_32 (abfd, (bfd_vma) value, PRIV (output_buf) + PRIV (output_size)); |
47eee8a9 | 823 | PRIV (output_size) += 4; |
252b5132 RH |
824 | } |
825 | ||
7920ce38 | 826 | /* Output quad (64 bit) value. */ |
252b5132 RH |
827 | |
828 | void | |
7920ce38 | 829 | _bfd_vms_output_quad (bfd * abfd, uquad value) |
252b5132 RH |
830 | { |
831 | #if VMS_DEBUG | |
7920ce38 | 832 | vms_debug (6, "_bfd_vms_output_quad (%016lx)\n", value); |
252b5132 RH |
833 | #endif |
834 | ||
47eee8a9 KH |
835 | bfd_put_64(abfd, value, PRIV (output_buf) + PRIV (output_size)); |
836 | PRIV (output_size) += 8; | |
252b5132 RH |
837 | } |
838 | ||
7920ce38 | 839 | /* Output c-string as counted string. */ |
252b5132 RH |
840 | |
841 | void | |
7920ce38 | 842 | _bfd_vms_output_counted (bfd * abfd, char *value) |
252b5132 | 843 | { |
7920ce38 | 844 | int len; |
252b5132 RH |
845 | |
846 | #if VMS_DEBUG | |
7920ce38 | 847 | vms_debug (6, "_bfd_vms_output_counted (%s)\n", value); |
252b5132 RH |
848 | #endif |
849 | ||
850 | len = strlen (value); | |
851 | if (len == 0) | |
852 | { | |
853 | (*_bfd_error_handler) (_("_bfd_vms_output_counted called with zero bytes")); | |
854 | return; | |
855 | } | |
856 | if (len > 255) | |
857 | { | |
858 | (*_bfd_error_handler) (_("_bfd_vms_output_counted called with too many bytes")); | |
859 | return; | |
860 | } | |
dc810e39 | 861 | _bfd_vms_output_byte (abfd, (unsigned int) len & 0xff); |
7920ce38 | 862 | _bfd_vms_output_dump (abfd, (unsigned char *) value, len); |
252b5132 RH |
863 | } |
864 | ||
7920ce38 | 865 | /* Output character area. */ |
252b5132 RH |
866 | |
867 | void | |
7920ce38 NC |
868 | _bfd_vms_output_dump (bfd * abfd, |
869 | unsigned char *data, | |
870 | int length) | |
252b5132 RH |
871 | { |
872 | #if VMS_DEBUG | |
7920ce38 | 873 | vms_debug (6, "_bfd_vms_output_dump (%d)\n", length); |
252b5132 RH |
874 | #endif |
875 | ||
876 | if (length == 0) | |
877 | return; | |
878 | ||
dc810e39 | 879 | memcpy (PRIV (output_buf) + PRIV (output_size), data, (size_t) length); |
47eee8a9 | 880 | PRIV (output_size) += length; |
252b5132 RH |
881 | } |
882 | ||
7920ce38 | 883 | /* Output count bytes of value. */ |
252b5132 RH |
884 | |
885 | void | |
7920ce38 NC |
886 | _bfd_vms_output_fill (bfd * abfd, |
887 | int value, | |
888 | int count) | |
252b5132 RH |
889 | { |
890 | #if VMS_DEBUG | |
7920ce38 | 891 | vms_debug (6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count); |
252b5132 RH |
892 | #endif |
893 | ||
894 | if (count == 0) | |
895 | return; | |
dc810e39 | 896 | memset (PRIV (output_buf) + PRIV (output_size), value, (size_t) count); |
47eee8a9 | 897 | PRIV (output_size) += count; |
252b5132 RH |
898 | } |
899 | ||
7920ce38 | 900 | /* This hash routine borrowed from GNU-EMACS, and strengthened slightly. ERY. */ |
252b5132 RH |
901 | |
902 | static int | |
7920ce38 | 903 | hash_string (const char *ptr) |
252b5132 | 904 | { |
7920ce38 NC |
905 | const unsigned char *p = (unsigned char *) ptr; |
906 | const unsigned char *end = p + strlen (ptr); | |
907 | unsigned char c; | |
908 | int hash = 0; | |
252b5132 RH |
909 | |
910 | while (p != end) | |
911 | { | |
912 | c = *p++; | |
913 | hash = ((hash << 3) + (hash << 15) + (hash >> 28) + c); | |
914 | } | |
915 | return hash; | |
916 | } | |
917 | ||
918 | /* Generate a length-hashed VMS symbol name (limited to maxlen chars). */ | |
919 | ||
920 | char * | |
7920ce38 | 921 | _bfd_vms_length_hash_symbol (bfd * abfd, const char *in, int maxlen) |
252b5132 | 922 | { |
0af1713e | 923 | unsigned long result; |
252b5132 | 924 | int in_len; |
252b5132 RH |
925 | char *new_name; |
926 | const char *old_name; | |
927 | int i; | |
928 | static char outbuf[EOBJ_S_C_SYMSIZ+1]; | |
929 | char *out = outbuf; | |
930 | ||
931 | #if VMS_DEBUG | |
7920ce38 | 932 | vms_debug (4, "_bfd_vms_length_hash_symbol \"%s\"\n", in); |
252b5132 RH |
933 | #endif |
934 | ||
935 | if (maxlen > EOBJ_S_C_SYMSIZ) | |
936 | maxlen = EOBJ_S_C_SYMSIZ; | |
937 | ||
7920ce38 NC |
938 | /* Save this for later. */ |
939 | new_name = out; | |
252b5132 RH |
940 | |
941 | /* We may need to truncate the symbol, save the hash for later. */ | |
252b5132 RH |
942 | in_len = strlen (in); |
943 | ||
944 | result = (in_len > maxlen) ? hash_string (in) : 0; | |
945 | ||
946 | old_name = in; | |
947 | ||
948 | /* Do the length checking. */ | |
252b5132 | 949 | if (in_len <= maxlen) |
7920ce38 | 950 | i = in_len; |
252b5132 RH |
951 | else |
952 | { | |
47eee8a9 | 953 | if (PRIV (flag_hash_long_names)) |
252b5132 RH |
954 | i = maxlen-9; |
955 | else | |
956 | i = maxlen; | |
957 | } | |
958 | ||
dc810e39 | 959 | strncpy (out, in, (size_t) i); |
252b5132 RH |
960 | in += i; |
961 | out += i; | |
962 | ||
963 | if ((in_len > maxlen) | |
47eee8a9 | 964 | && PRIV (flag_hash_long_names)) |
e049a0de | 965 | sprintf (out, "_%08lx", result); |
252b5132 RH |
966 | else |
967 | *out = 0; | |
968 | ||
969 | #if VMS_DEBUG | |
7920ce38 | 970 | vms_debug (4, "--> [%d]\"%s\"\n", strlen (outbuf), outbuf); |
252b5132 RH |
971 | #endif |
972 | ||
973 | if (in_len > maxlen | |
47eee8a9 KH |
974 | && PRIV (flag_hash_long_names) |
975 | && PRIV (flag_show_after_trunc)) | |
252b5132 RH |
976 | printf (_("Symbol %s replaced by %s\n"), old_name, new_name); |
977 | ||
978 | return outbuf; | |
979 | } | |
980 | ||
252b5132 RH |
981 | /* Allocate and initialize a new symbol. */ |
982 | ||
983 | static asymbol * | |
7920ce38 | 984 | new_symbol (bfd * abfd, char *name) |
252b5132 RH |
985 | { |
986 | asymbol *symbol; | |
987 | ||
988 | #if VMS_DEBUG | |
989 | _bfd_vms_debug (7, "new_symbol %s\n", name); | |
990 | #endif | |
991 | ||
3f3c5c34 | 992 | symbol = bfd_make_empty_symbol (abfd); |
252b5132 RH |
993 | if (symbol == 0) |
994 | return symbol; | |
995 | symbol->name = name; | |
0c376465 | 996 | symbol->section = (asection *)(unsigned long)-1; |
252b5132 RH |
997 | |
998 | return symbol; | |
999 | } | |
1000 | ||
252b5132 RH |
1001 | /* Allocate and enter a new private symbol. */ |
1002 | ||
1003 | vms_symbol_entry * | |
7920ce38 | 1004 | _bfd_vms_enter_symbol (bfd * abfd, char *name) |
252b5132 RH |
1005 | { |
1006 | vms_symbol_entry *entry; | |
1007 | ||
1008 | #if VMS_DEBUG | |
1009 | _bfd_vms_debug (6, "_bfd_vms_enter_symbol %s\n", name); | |
1010 | #endif | |
1011 | ||
1012 | entry = (vms_symbol_entry *) | |
b34976b6 | 1013 | bfd_hash_lookup (PRIV (vms_symbol_table), name, FALSE, FALSE); |
252b5132 RH |
1014 | if (entry == 0) |
1015 | { | |
1016 | #if VMS_DEBUG | |
1017 | _bfd_vms_debug (8, "creating hash entry for %s\n", name); | |
1018 | #endif | |
b34976b6 AM |
1019 | entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table), |
1020 | name, TRUE, FALSE); | |
252b5132 RH |
1021 | if (entry != 0) |
1022 | { | |
1023 | asymbol *symbol; | |
1024 | symbol = new_symbol (abfd, name); | |
1025 | if (symbol != 0) | |
1026 | { | |
1027 | entry->symbol = symbol; | |
47eee8a9 | 1028 | PRIV (gsd_sym_count)++; |
252b5132 RH |
1029 | abfd->symcount++; |
1030 | } | |
1031 | else | |
1032 | entry = 0; | |
1033 | } | |
1034 | else | |
1035 | (*_bfd_error_handler) (_("failed to enter %s"), name); | |
1036 | } | |
1037 | else | |
1038 | { | |
1039 | #if VMS_DEBUG | |
1040 | _bfd_vms_debug (8, "found hash entry for %s\n", name); | |
1041 | #endif | |
1042 | } | |
1043 | ||
1044 | #if VMS_DEBUG | |
1045 | _bfd_vms_debug (7, "-> entry %p, entry->symbol %p\n", entry, entry->symbol); | |
1046 | #endif | |
1047 | return entry; | |
1048 | } | |
4b544b64 TG |
1049 | |
1050 | /* Create module name from filename (ie, extract the basename and convert it | |
1051 | in upper cases). Works on both VMS and UNIX pathes. | |
1052 | The result has to be free(). */ | |
1053 | ||
1054 | char * | |
1055 | vms_get_module_name (const char *filename, bfd_boolean upcase) | |
1056 | { | |
1057 | char *fname, *fptr; | |
1058 | const char *fout; | |
1059 | ||
1060 | /* Strip VMS path. */ | |
1061 | fout = strrchr (filename, ']'); | |
1062 | if (fout == NULL) | |
1063 | fout = strchr (filename, ':'); | |
1064 | if (fout != NULL) | |
1065 | fout++; | |
1066 | else | |
1067 | fout = filename; | |
1068 | ||
1069 | /* Strip UNIX path. */ | |
1070 | fptr = strrchr (fout, '/'); | |
1071 | if (fptr != NULL) | |
1072 | fout = fptr + 1; | |
1073 | ||
1074 | fname = strdup (fout); | |
1075 | ||
1076 | /* Strip suffix. */ | |
1077 | fptr = strrchr (fname, '.'); | |
1078 | if (fptr != 0) | |
1079 | *fptr = 0; | |
1080 | ||
1081 | /* Convert to upper case and truncate at 31 characters. | |
1082 | (VMS object file format restricts module name length to 31). */ | |
1083 | fptr = fname; | |
1084 | for (fptr = fname; *fptr != 0; fptr++) | |
1085 | { | |
1086 | if (*fptr == ';' || (fptr - fname) >= 31) | |
1087 | { | |
1088 | *fptr = 0; | |
1089 | break; | |
1090 | } | |
1091 | if (upcase) | |
1092 | *fptr = TOUPPER (*fptr); | |
1093 | } | |
1094 | return fname; | |
1095 | } | |
1096 | ||
1097 | /* Convert a raw VMS time to a unix time. */ | |
1098 | ||
1099 | time_t | |
1100 | vms_time_to_time_t (unsigned int hi, unsigned int lo) | |
1101 | { | |
1102 | const unsigned int off = 3506716800U; | |
1103 | const unsigned int factor = 10000000; | |
1104 | unsigned int tmp; | |
1105 | unsigned int rlo; | |
1106 | int i; | |
1107 | ||
1108 | /* First convert to seconds. */ | |
1109 | tmp = hi % factor; | |
1110 | hi = hi / factor; | |
1111 | rlo = 0; | |
1112 | for (i = 0; i < 4; i++) | |
1113 | { | |
1114 | tmp = (tmp << 8) | (lo >> 24); | |
1115 | lo <<= 8; | |
1116 | ||
1117 | rlo = (rlo << 8) | (tmp / factor); | |
1118 | tmp %= factor; | |
1119 | } | |
1120 | lo = rlo; | |
1121 | ||
1122 | /* Return 0 in case of overflow. */ | |
1123 | if (lo > off && hi > 1) | |
1124 | return 0; | |
1125 | ||
1126 | return lo - off; | |
1127 | } | |
1128 | ||
1129 | /* Convert a raw (stored in a buffer) VMS time to a unix time. */ | |
1130 | ||
1131 | time_t | |
1132 | vms_rawtime_to_time_t (unsigned char *buf) | |
1133 | { | |
1134 | unsigned int hi = bfd_getl32 (buf + 4); | |
1135 | unsigned int lo = bfd_getl32 (buf + 0); | |
1136 | ||
1137 | return vms_time_to_time_t (hi, lo); | |
1138 | } |