X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Fvms-misc.c;h=bc422895bd02a2369ab9dec30ad08fe55c089c32;hb=99a5596592eda72c5c60b45cdfabb47e426132d5;hp=47e598559b181c763930feee88e53f951fc4f414;hpb=771deb084eb2128196b9057996847719583be713;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/vms-misc.c b/bfd/vms-misc.c index 47e598559b..bc422895bd 100644 --- a/bfd/vms-misc.c +++ b/bfd/vms-misc.c @@ -1,7 +1,6 @@ /* vms-misc.c -- BFD back-end for VMS/VAX (openVMS/VAX) and EVAX (openVMS/Alpha) files. - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2007, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 1996-2019 Free Software Foundation, Inc. Miscellaneous functions. @@ -30,16 +29,21 @@ #include "bfd.h" #include "bfdlink.h" #include "libbfd.h" +#include "safe-ctype.h" -#include "vms.h" - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#ifdef VMS +#define __NEW_STARLET +#include +#include +#include +#include +#define RME$C_SETRFM 0x00000001 +#include +#endif +#include -static int hash_string PARAMS ((const char *)); -static asymbol *new_symbol PARAMS ((bfd *, char *)); -static void maybe_adjust_record_pointer_for_object PARAMS ((bfd *)); -static int vms_get_remaining_object_record PARAMS ((bfd *, int )); -static int vms_get_remaining_image_record PARAMS ((bfd *, int )); +#include "vms.h" +#include "vms/emh.h" #if VMS_DEBUG /* Debug functions. */ @@ -81,7 +85,7 @@ _bfd_vms_debug (int level, char *format, ...) if (abslvl > min_level) return; - while (--level>0) + while (--level > 0) fprintf (output, " "); va_start (args, format); vfprintf (output, format, args); @@ -93,10 +97,7 @@ _bfd_vms_debug (int level, char *format, ...) hex dump 'size' bytes starting at 'ptr'. */ void -_bfd_hexdump (int level, - unsigned char *ptr, - int size, - int offset) +_bfd_hexdump (int level, unsigned char *ptr, int size, int offset) { unsigned char *lptr = ptr; int count = 0; @@ -104,944 +105,568 @@ _bfd_hexdump (int level, while (size-- > 0) { - if ((count%16) == 0) + if ((count % 16) == 0) vms_debug (level, "%08lx:", start); vms_debug (-level, " %02x", *ptr++); count++; start++; if (size == 0) { - while ((count%16) != 0) + while ((count % 16) != 0) { vms_debug (-level, " "); count++; } } - if ((count%16) == 0) + if ((count % 16) == 0) { vms_debug (-level, " "); while (lptr < ptr) { - vms_debug (-level, "%c", (*lptr < 32)?'.':*lptr); + vms_debug (-level, "%c", (*lptr < 32) ? '.' : *lptr); lptr++; } vms_debug (-level, "\n"); } } - if ((count%16) != 0) + if ((count % 16) != 0) vms_debug (-level, "\n"); } #endif -/* Hash functions - - These are needed when reading an object file. */ - -/* Allocate new vms_hash_entry - keep the symbol name and a pointer to the bfd symbol in the table. */ - -struct bfd_hash_entry * -_bfd_vms_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - vms_symbol_entry *ret; - -#if VMS_DEBUG - vms_debug (5, "_bfd_vms_hash_newfunc (%p, %p, %s)\n", entry, table, string); -#endif - - if (entry == NULL) - { - ret = (vms_symbol_entry *) - bfd_hash_allocate (table, sizeof (vms_symbol_entry)); - if (ret == NULL) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } - entry = (struct bfd_hash_entry *) ret; - } - - /* Call the allocation method of the base class. */ - ret = (vms_symbol_entry *) bfd_hash_newfunc (entry, table, string); -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_hash_newfunc ret %p\n", ret); -#endif - - ret->symbol = NULL; - - return (struct bfd_hash_entry *)ret; -} - -/* Object file input functions. */ - -/* Return type and size from record header (buf) on Alpha. */ - -void -_bfd_vms_get_header_values (bfd * abfd ATTRIBUTE_UNUSED, - unsigned char *buf, - int *type, - int *size) -{ - if (type) - *type = bfd_getl16 (buf); - - if (size) - *size = bfd_getl16 (buf+2); - -#if VMS_DEBUG - vms_debug (10, "_bfd_vms_get_header_values type %x, size %x\n", - type ? *type : 0, size ? *size : 0); -#endif -} - -/* Get next record from object file to vms_buf. - Set PRIV(buf_size) and return it - - This is a little tricky since it should be portable. - - The openVMS object file has 'variable length' which means that - read() returns data in chunks of (hopefully) correct and expected - size. The linker (and other tools on VMS) depend on that. Unix - doesn't know about 'formatted' files, so reading and writing such - an object file in a Unix environment is not trivial. - - With the tool 'file' (available on all VMS FTP sites), one - can view and change the attributes of a file. Changing from - 'variable length' to 'fixed length, 512 bytes' reveals the - record size at the first 2 bytes of every record. The same - may happen during the transfer of object files from VMS to Unix, - at least with UCX, the DEC implementation of TCP/IP. - - The VMS format repeats the size at bytes 2 & 3 of every record. - - On the first call (file_format == FF_UNKNOWN) we check if - the first and the third byte pair (!) of the record match. - If they do it's an object file in an Unix environment or with - wrong attributes (FF_FOREIGN), else we should be in a VMS - environment where read() returns the record size (FF_NATIVE). - - Reading is always done in 2 steps: - 1. first just the record header is read and the size extracted, - 2. then the read buffer is adjusted and the remaining bytes are - read in. - - All file I/O is done on even file positions. */ - -#define VMS_OBJECT_ADJUSTMENT 2 - -static void -maybe_adjust_record_pointer_for_object (bfd *abfd) -{ - /* Set the file format once for all on the first invocation. */ - if (PRIV (file_format) == FF_UNKNOWN) - { - if (PRIV (vms_rec)[0] == PRIV (vms_rec)[4] - && PRIV (vms_rec)[1] == PRIV (vms_rec)[5]) - PRIV (file_format) = FF_FOREIGN; - else - PRIV (file_format) = FF_NATIVE; - } - - /* The adjustment is needed only in an Unix environment. */ - if (PRIV (file_format) == FF_FOREIGN) - PRIV (vms_rec) += VMS_OBJECT_ADJUSTMENT; -} - -/* Get first record from file and return the file type. */ - -int -_bfd_vms_get_first_record (bfd *abfd) -{ - unsigned int test_len; - -#if VMS_DEBUG - vms_debug (8, "_bfd_vms_get_first_record\n"); -#endif - - if (PRIV (is_vax)) - test_len = 0; - else - /* Minimum is 6 bytes for objects (2 bytes size, 2 bytes record id, - 2 bytes size repeated) and 12 bytes for images (4 bytes major id, - 4 bytes minor id, 4 bytes length). */ - test_len = 12; - - /* Size the main buffer. */ - if (PRIV (buf_size) == 0) - { - /* On VAX there's no size information in the record, so - start with OBJ_S_C_MAXRECSIZ. */ - bfd_size_type amt = (test_len ? test_len : OBJ_S_C_MAXRECSIZ); - PRIV (vms_buf) = (unsigned char *) bfd_malloc (amt); - PRIV (buf_size) = amt; - } - - /* Initialize the record pointer. */ - PRIV (vms_rec) = PRIV (vms_buf); - - /* We only support modules on VAX. */ - if (PRIV (is_vax)) - { - if (vms_get_remaining_object_record (abfd, test_len) <= 0) - return FT_UNKNOWN; - -#if VMS_DEBUG - vms_debug (2, "file type is VAX module\n"); -#endif - - return FT_MODULE; - } - - if (bfd_bread (PRIV (vms_buf), test_len, abfd) != test_len) - { - bfd_set_error (bfd_error_file_truncated); - return FT_UNKNOWN; - } - - /* Is it an image? */ - if ((bfd_getl32 (PRIV (vms_rec)) == EIHD_S_K_MAJORID) - && (bfd_getl32 (PRIV (vms_rec) + 4) == EIHD_S_K_MINORID)) - { - if (vms_get_remaining_image_record (abfd, test_len) <= 0) - return FT_UNKNOWN; - -#if VMS_DEBUG - vms_debug (2, "file type is image\n"); -#endif - - return FT_IMAGE; - } - - /* Assume it's a module and adjust record pointer if necessary. */ - maybe_adjust_record_pointer_for_object (abfd); - - /* But is it really a module? */ - if (bfd_getl16 (PRIV (vms_rec)) <= EOBJ_S_C_MAXRECTYP - && bfd_getl16 (PRIV (vms_rec) + 2) <= EOBJ_S_C_MAXRECSIZ) - { - if (vms_get_remaining_object_record (abfd, test_len) <= 0) - return FT_UNKNOWN; - -#if VMS_DEBUG - vms_debug (2, "file type is module\n"); -#endif - - return FT_MODULE; - } - -#if VMS_DEBUG - vms_debug (2, "file type is unknown\n"); -#endif - - return FT_UNKNOWN; -} - -/* Implement step #1 of the object record reading procedure. - Return the record type or -1 on failure. */ - -int -_bfd_vms_get_object_record (bfd *abfd) -{ - unsigned int test_len; - int type; - -#if VMS_DEBUG - vms_debug (8, "_bfd_vms_get_obj_record\n"); -#endif - - if (PRIV (is_vax)) - test_len = 0; - else - { - int off = 0; - - /* See _bfd_vms_get_first_record. */ - test_len = 6; - - /* Skip odd alignment byte. */ - if (bfd_tell (abfd) & 1) - { - if (bfd_bread (PRIV (vms_buf), 1, abfd) != 1) - { - bfd_set_error (bfd_error_file_truncated); - return -1; - } - /* Alignment byte may be present or not. This is not easy to - detect but all object record types are not 0 (on Alpha VMS). - We also hope that pad byte is 0. */ - if (PRIV (vms_buf)[0]) - off = 1; - } - - /* Read the record header */ - if (bfd_bread (PRIV (vms_buf) + off, test_len - off, abfd) - != test_len - off) - { - bfd_set_error (bfd_error_file_truncated); - return -1; - } - - /* Reset the record pointer. */ - PRIV (vms_rec) = PRIV (vms_buf); - maybe_adjust_record_pointer_for_object (abfd); - } - - if (vms_get_remaining_object_record (abfd, test_len) <= 0) - return -1; - - if (PRIV (is_vax)) - type = PRIV (vms_rec) [0]; - else - type = bfd_getl16 (PRIV (vms_rec)); - -#if VMS_DEBUG - vms_debug (8, "_bfd_vms_get_obj_record: rec %p, size %d, type %d\n", - PRIV (vms_rec), PRIV (rec_size), type); -#endif - - return type; -} - -/* Implement step #2 of the object record reading procedure. - Return the size of the record or 0 on failure. */ - -static int -vms_get_remaining_object_record (bfd *abfd, int read_so_far) -{ -#if VMS_DEBUG - vms_debug (8, "vms_get_remaining_obj_record\n"); -#endif - - if (PRIV (is_vax)) - { - if (read_so_far != 0) - abort (); - - PRIV (rec_size) = bfd_bread (PRIV (vms_buf), PRIV (buf_size), abfd); - - if (PRIV (rec_size) <= 0) - { - bfd_set_error (bfd_error_file_truncated); - return 0; - } - - /* Reset the record pointer. */ - PRIV (vms_rec) = PRIV (vms_buf); - } - else - { - unsigned int to_read; - - /* Extract record size. */ - PRIV (rec_size) = bfd_getl16 (PRIV (vms_rec) + 2); - - if (PRIV (rec_size) <= 0) - { - bfd_set_error (bfd_error_file_truncated); - return 0; - } - - /* That's what the linker manual says. */ - if (PRIV (rec_size) > EOBJ_S_C_MAXRECSIZ) - { - bfd_set_error (bfd_error_file_truncated); - return 0; - } - - /* Take into account object adjustment. */ - to_read = PRIV (rec_size); - if (PRIV (file_format) == FF_FOREIGN) - to_read += VMS_OBJECT_ADJUSTMENT; - - /* Adjust the buffer. */ - if (to_read > PRIV (buf_size)) - { - PRIV (vms_buf) - = (unsigned char *) bfd_realloc (PRIV (vms_buf), to_read); - if (PRIV (vms_buf) == NULL) - return 0; - PRIV (buf_size) = to_read; - } - - /* Read the remaining record. */ - to_read -= read_so_far; - -#if VMS_DEBUG - vms_debug (8, "vms_get_remaining_obj_record: to_read %d\n", to_read); -#endif - - if (bfd_bread (PRIV (vms_buf) + read_so_far, to_read, abfd) != to_read) - { - bfd_set_error (bfd_error_file_truncated); - return 0; - } - - /* Reset the record pointer. */ - PRIV (vms_rec) = PRIV (vms_buf); - maybe_adjust_record_pointer_for_object (abfd); - } - -#if VMS_DEBUG - vms_debug (8, "vms_get_remaining_obj_record: size %d\n", PRIV (rec_size)); -#endif - - return PRIV (rec_size); -} - -/* Implement step #2 of the record reading procedure for images. - Return the size of the record or 0 on failure. */ - -static int -vms_get_remaining_image_record (bfd *abfd, int read_so_far) -{ - unsigned int to_read; - int remaining; - - /* Extract record size. */ - PRIV (rec_size) = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_SIZE); - - if (PRIV (rec_size) > PRIV (buf_size)) - { - PRIV (vms_buf) = bfd_realloc (PRIV (vms_buf), PRIV (rec_size)); - - if (PRIV (vms_buf) == NULL) - { - bfd_set_error (bfd_error_no_memory); - return 0; - } - - PRIV (buf_size) = PRIV (rec_size); - } - /* Read the remaining record. */ - remaining = PRIV (rec_size) - read_so_far; - to_read = MIN (VMS_BLOCK_SIZE - read_so_far, remaining); - - while (remaining > 0) - { - if (bfd_bread (PRIV (vms_buf) + read_so_far, to_read, abfd) != to_read) - { - bfd_set_error (bfd_error_file_truncated); - return 0; - } - - read_so_far += to_read; - remaining -= to_read; - - /* Eat trailing 0xff's. */ - if (remaining > 0) - while (PRIV (vms_buf) [read_so_far - 1] == 0xff) - read_so_far--; - - to_read = MIN (VMS_BLOCK_SIZE, remaining); - } - - /* Reset the record pointer. */ - PRIV (vms_rec) = PRIV (vms_buf); - - return PRIV (rec_size); -} - -/* Copy sized string (string with fixed size) to new allocated area - size is string size (size of record) */ +/* Copy sized string (string with fixed size) to new allocated area. + Size is string size (size of record). */ char * -_bfd_vms_save_sized_string (unsigned char *str, int size) +_bfd_vms_save_sized_string (unsigned char *str, unsigned int size) { char *newstr = bfd_malloc ((bfd_size_type) size + 1); if (newstr == NULL) return NULL; - strncpy (newstr, (char *) str, (size_t) size); + memcpy (newstr, (char *) str, (size_t) size); newstr[size] = 0; return newstr; } -/* Copy counted string (string with size at first byte) to new allocated area - ptr points to size byte on entry */ +/* Copy counted string (string with size at first byte) to new allocated area. + PTR points to size byte on entry. */ char * -_bfd_vms_save_counted_string (unsigned char *ptr) +_bfd_vms_save_counted_string (unsigned char *ptr, unsigned int maxlen) { - int len = *ptr++; + unsigned int len = *ptr++; + if (len > maxlen) + return NULL; return _bfd_vms_save_sized_string (ptr, len); } -/* Stack routines for vms ETIR commands. */ +/* Object output routines. */ -/* Push value and section index. */ +/* Begin new record. + Write 2 bytes rectype and 2 bytes record length. */ void -_bfd_vms_push (bfd * abfd, uquad val, int psect) -{ - static int last_psect; - -#if VMS_DEBUG - vms_debug (4, "\n", val, psect, PRIV (stackptr)); -#endif - - if (psect >= 0) - last_psect = psect; - - PRIV (stack[PRIV (stackptr)]).value = val; - PRIV (stack[PRIV (stackptr)]).psect = last_psect; - PRIV (stackptr)++; - if (PRIV (stackptr) >= STACKSIZE) - { - bfd_set_error (bfd_error_bad_value); - (*_bfd_error_handler) (_("Stack overflow (%d) in _bfd_vms_push"), PRIV (stackptr)); - exit (1); - } -} - -/* Pop value and section index. */ - -uquad -_bfd_vms_pop (bfd * abfd, int *psect) +_bfd_vms_output_begin (struct vms_rec_wr *recwr, int rectype) { - uquad value; + vms_debug2 ((6, "_bfd_vms_output_begin (type %d)\n", rectype)); - if (PRIV (stackptr) == 0) - { - bfd_set_error (bfd_error_bad_value); - (*_bfd_error_handler) (_("Stack underflow in _bfd_vms_pop")); - exit (1); - } - PRIV (stackptr)--; - value = PRIV (stack[PRIV (stackptr)]).value; - if ((psect != NULL) && (PRIV (stack[PRIV (stackptr)]).psect >= 0)) - *psect = PRIV (stack[PRIV (stackptr)]).psect; + /* Record must have been closed. */ + BFD_ASSERT (recwr->size == 0); -#if VMS_DEBUG - vms_debug (4, "\n", value, PRIV (stack[PRIV (stackptr)]).psect); -#endif + _bfd_vms_output_short (recwr, (unsigned int) rectype); - return value; + /* Placeholder for length. */ + _bfd_vms_output_short (recwr, 0); } - -/* Object output routines. */ -/* Begin new record or record header - write 2 bytes rectype - write 2 bytes record length (filled in at flush) - write 2 bytes header type (ommitted if rechead == -1). */ +/* Begin new sub-record. + Write 2 bytes rectype, and 2 bytes record length. */ void -_bfd_vms_output_begin (bfd * abfd, int rectype, int rechead) +_bfd_vms_output_begin_subrec (struct vms_rec_wr *recwr, int rectype) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_begin (type %d, head %d)\n", rectype, - rechead); -#endif - - _bfd_vms_output_short (abfd, (unsigned int) rectype); + vms_debug2 ((6, "_bfd_vms_output_begin_subrec (type %d)\n", rectype)); - /* Save current output position to fill in length later. */ + /* Subrecord must have been closed. */ + BFD_ASSERT (recwr->subrec_offset == 0); - if (PRIV (push_level) > 0) - PRIV (length_pos) = PRIV (output_size); + /* Save start of subrecord offset. */ + recwr->subrec_offset = recwr->size; -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_begin: length_pos = %d\n", - PRIV (length_pos)); -#endif + /* Subrecord type. */ + _bfd_vms_output_short (recwr, (unsigned int) rectype); /* Placeholder for length. */ - _bfd_vms_output_short (abfd, 0); - - if (rechead != -1) - _bfd_vms_output_short (abfd, (unsigned int) rechead); + _bfd_vms_output_short (recwr, 0); } /* Set record/subrecord alignment. */ void -_bfd_vms_output_alignment (bfd * abfd, int alignto) +_bfd_vms_output_alignment (struct vms_rec_wr *recwr, int alignto) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_alignment (%d)\n", alignto); -#endif - - PRIV (output_alignment) = alignto; + vms_debug2 ((6, "_bfd_vms_output_alignment (%d)\n", alignto)); + recwr->align = alignto; } -/* Prepare for subrecord fields. */ +/* Align the size of the current record (whose length is LENGTH). + Warning: this obviously changes the record (and the possible subrecord) + length. */ -void -_bfd_vms_output_push (bfd * abfd) -{ -#if VMS_DEBUG - vms_debug (6, "vms_output_push (pushed_size = %d)\n", PRIV (output_size)); -#endif - - PRIV (push_level)++; - PRIV (pushed_size) = PRIV (output_size); -} - -/* End of subrecord fields. */ - -void -_bfd_vms_output_pop (bfd * abfd) +static void +_bfd_vms_output_align (struct vms_rec_wr *recwr, unsigned int length) { -#if VMS_DEBUG - vms_debug (6, "vms_output_pop (pushed_size = %d)\n", PRIV (pushed_size)); -#endif + unsigned int real_size = recwr->size; + unsigned int aligncount; - _bfd_vms_output_flush (abfd); - PRIV (length_pos) = 2; - -#if VMS_DEBUG - vms_debug (6, "vms_output_pop: length_pos = %d\n", PRIV (length_pos)); -#endif + /* Pad with 0 if alignment is required. */ + aligncount = (recwr->align - (length % recwr->align)) % recwr->align; + vms_debug2 ((6, "align: adding %d bytes\n", aligncount)); + while (aligncount-- > 0) + recwr->buf[real_size++] = 0; - PRIV (pushed_size) = 0; - PRIV (push_level)--; + recwr->size = real_size; } -/* Flush unwritten output, ends current record. */ +/* Ends current sub-record. Set length field. */ void -_bfd_vms_output_flush (bfd * abfd) +_bfd_vms_output_end_subrec (struct vms_rec_wr *recwr) { - int real_size = PRIV (output_size); - int aligncount; + int real_size = recwr->size; int length; -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_flush (real_size = %d, pushed_size %d at lenpos %d)\n", - real_size, PRIV (pushed_size), PRIV (length_pos)); -#endif + /* Subrecord must be open. */ + BFD_ASSERT (recwr->subrec_offset != 0); - if (PRIV (push_level) > 0) - length = real_size - PRIV (pushed_size); - else - length = real_size; + length = real_size - recwr->subrec_offset; if (length == 0) return; - aligncount = (PRIV (output_alignment) - - (length % PRIV (output_alignment))) % PRIV (output_alignment); -#if VMS_DEBUG - vms_debug (6, "align: adding %d bytes\n", aligncount); -#endif - - while (aligncount-- > 0) - { - PRIV (output_buf)[real_size++] = 0; - length++; - } + _bfd_vms_output_align (recwr, length); /* Put length to buffer. */ - PRIV (output_size) = PRIV (length_pos); - _bfd_vms_output_short (abfd, (unsigned int) length); + bfd_putl16 ((bfd_vma) (recwr->size - recwr->subrec_offset), + recwr->buf + recwr->subrec_offset + 2); - if (PRIV (push_level) == 0) - { - /* File is open in undefined (UDF) format on VMS, but ultimately will be - converted to variable length (VAR) format. VAR format has a length - word first which must be explicitly output in UDF format. */ - bfd_bwrite (PRIV (output_buf) + 2, 2, abfd); - bfd_bwrite (PRIV (output_buf), (size_t) real_size, abfd); - PRIV (output_size) = 0; - } - else - { - PRIV (output_size) = real_size; - PRIV (pushed_size) = PRIV (output_size); - } + /* Close the subrecord. */ + recwr->subrec_offset = 0; } -/* End record output. */ +/* Ends current record (and write it). */ void -_bfd_vms_output_end (bfd * abfd) +_bfd_vms_output_end (bfd *abfd, struct vms_rec_wr *recwr) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_end\n"); -#endif + vms_debug2 ((6, "_bfd_vms_output_end (size %u)\n", recwr->size)); - _bfd_vms_output_flush (abfd); -} + /* Subrecord must have been closed. */ + BFD_ASSERT (recwr->subrec_offset == 0); + + if (recwr->size == 0) + return; + + _bfd_vms_output_align (recwr, recwr->size); -/* Check remaining buffer size + /* Write the length word. */ + bfd_putl16 ((bfd_vma) recwr->size, recwr->buf + 2); - Return what's left. */ + /* File is open in undefined (UDF) format on VMS, but ultimately will be + converted to variable length (VAR) format. VAR format has a length + word first which must be explicitly output in UDF format. */ + /* So, first the length word. */ + bfd_bwrite (recwr->buf + 2, 2, abfd); + + /* Align. */ + if (recwr->size & 1) + recwr->buf[recwr->size++] = 0; + + /* Then the record. */ + bfd_bwrite (recwr->buf, (size_t) recwr->size, abfd); + + recwr->size = 0; +} + +/* Check remaining buffer size. Return what's left. */ int -_bfd_vms_output_check (bfd * abfd, int size) +_bfd_vms_output_check (struct vms_rec_wr *recwr, int size) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_check (%d)\n", size); -#endif + vms_debug2 ((6, "_bfd_vms_output_check (%d)\n", size)); - return (MAX_OUTREC_SIZE - (PRIV (output_size) + size + MIN_OUTREC_LUFT)); + return (MAX_OUTREC_SIZE - (recwr->size + size + MIN_OUTREC_LUFT)); } /* Output byte (8 bit) value. */ void -_bfd_vms_output_byte (bfd * abfd, unsigned int value) +_bfd_vms_output_byte (struct vms_rec_wr *recwr, unsigned int value) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_byte (%02x)\n", value); -#endif + vms_debug2 ((6, "_bfd_vms_output_byte (%02x)\n", value)); - bfd_put_8 (abfd, value & 0xff, PRIV (output_buf) + PRIV (output_size)); - PRIV (output_size) += 1; + *(recwr->buf + recwr->size) = value; + recwr->size += 1; } /* Output short (16 bit) value. */ void -_bfd_vms_output_short (bfd * abfd, unsigned int value) +_bfd_vms_output_short (struct vms_rec_wr *recwr, unsigned int value) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_short (%04x)\n", value); -#endif + vms_debug2 ((6, "_bfd_vms_output_short (%04x)\n", value)); - bfd_put_16 (abfd, (bfd_vma) value & 0xffff, - PRIV (output_buf) + PRIV (output_size)); - PRIV (output_size) += 2; + bfd_putl16 ((bfd_vma) value & 0xffff, recwr->buf + recwr->size); + recwr->size += 2; } /* Output long (32 bit) value. */ void -_bfd_vms_output_long (bfd * abfd, unsigned long value) +_bfd_vms_output_long (struct vms_rec_wr *recwr, unsigned long value) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_long (%08lx)\n", value); -#endif + vms_debug2 ((6, "_bfd_vms_output_long (%08lx)\n", value)); - bfd_put_32 (abfd, (bfd_vma) value, PRIV (output_buf) + PRIV (output_size)); - PRIV (output_size) += 4; + bfd_putl32 ((bfd_vma) value, recwr->buf + recwr->size); + recwr->size += 4; } /* Output quad (64 bit) value. */ void -_bfd_vms_output_quad (bfd * abfd, uquad value) +_bfd_vms_output_quad (struct vms_rec_wr *recwr, bfd_vma value) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_quad (%016lx)\n", value); -#endif + vms_debug2 ((6, "_bfd_vms_output_quad (%08lx)\n", (unsigned long)value)); - bfd_put_64(abfd, value, PRIV (output_buf) + PRIV (output_size)); - PRIV (output_size) += 8; + bfd_putl64 (value, recwr->buf + recwr->size); + recwr->size += 8; } /* Output c-string as counted string. */ void -_bfd_vms_output_counted (bfd * abfd, char *value) +_bfd_vms_output_counted (struct vms_rec_wr *recwr, const char *value) { int len; -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_counted (%s)\n", value); -#endif + vms_debug2 ((6, "_bfd_vms_output_counted (%s)\n", value)); len = strlen (value); if (len == 0) { - (*_bfd_error_handler) (_("_bfd_vms_output_counted called with zero bytes")); + _bfd_error_handler (_("_bfd_vms_output_counted called with zero bytes")); return; } if (len > 255) { - (*_bfd_error_handler) (_("_bfd_vms_output_counted called with too many bytes")); + _bfd_error_handler (_("_bfd_vms_output_counted called with too many bytes")); return; } - _bfd_vms_output_byte (abfd, (unsigned int) len & 0xff); - _bfd_vms_output_dump (abfd, (unsigned char *) value, len); + _bfd_vms_output_byte (recwr, (unsigned int) len & 0xff); + _bfd_vms_output_dump (recwr, (const unsigned char *)value, len); } /* Output character area. */ void -_bfd_vms_output_dump (bfd * abfd, - unsigned char *data, - int length) +_bfd_vms_output_dump (struct vms_rec_wr *recwr, const unsigned char *data, int len) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_dump (%d)\n", length); -#endif + vms_debug2 ((6, "_bfd_vms_output_dump (%d)\n", len)); - if (length == 0) + if (len == 0) return; - memcpy (PRIV (output_buf) + PRIV (output_size), data, (size_t) length); - PRIV (output_size) += length; + memcpy (recwr->buf + recwr->size, data, (size_t) len); + recwr->size += len; } /* Output count bytes of value. */ void -_bfd_vms_output_fill (bfd * abfd, - int value, - int count) +_bfd_vms_output_fill (struct vms_rec_wr *recwr, int value, int count) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count); -#endif + vms_debug2 ((6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count)); if (count == 0) return; - memset (PRIV (output_buf) + PRIV (output_size), value, (size_t) count); - PRIV (output_size) += count; + memset (recwr->buf + recwr->size, value, (size_t) count); + recwr->size += count; } -/* This hash routine borrowed from GNU-EMACS, and strengthened slightly. ERY. */ +#ifdef VMS +/* Convert the file to variable record length format. This is done + using undocumented system call sys$modify(). + Pure VMS version. */ -static int -hash_string (const char *ptr) +static void +vms_convert_to_var (char * vms_filename) { - const unsigned char *p = (unsigned char *) ptr; - const unsigned char *end = p + strlen (ptr); - unsigned char c; - int hash = 0; + struct FAB fab = cc$rms_fab; - while (p != end) - { - c = *p++; - hash = ((hash << 3) + (hash << 15) + (hash >> 28) + c); - } - return hash; + fab.fab$l_fna = vms_filename; + fab.fab$b_fns = strlen (vms_filename); + fab.fab$b_fac = FAB$M_PUT; + fab.fab$l_fop = FAB$M_ESC; + fab.fab$l_ctx = RME$C_SETRFM; + + sys$open (&fab); + + fab.fab$b_rfm = FAB$C_VAR; + + sys$modify (&fab); + sys$close (&fab); +} + +static int +vms_convert_to_var_1 (char *filename, int type) +{ + if (type != DECC$K_FILE) + return FALSE; + vms_convert_to_var (filename); + return TRUE; } -/* Generate a length-hashed VMS symbol name (limited to maxlen chars). */ +/* Convert the file to variable record length format. This is done + using undocumented system call sys$modify(). + Unix filename version. */ -char * -_bfd_vms_length_hash_symbol (bfd * abfd, const char *in, int maxlen) +int +_bfd_vms_convert_to_var_unix_filename (const char *unix_filename) { - unsigned long result; - int in_len; - char *new_name; - const char *old_name; - int i; - static char outbuf[EOBJ_S_C_SYMSIZ+1]; - char *out = outbuf; + if (decc$to_vms (unix_filename, &vms_convert_to_var_1, 0, 1) != 1) + return FALSE; + return TRUE; +} +#endif /* VMS */ -#if VMS_DEBUG - vms_debug (4, "_bfd_vms_length_hash_symbol \"%s\"\n", in); -#endif +/* Manufacture a VMS like time on a unix based system. + stolen from obj-vms.c. */ + +unsigned char * +get_vms_time_string (void) +{ + static unsigned char tbuf[18]; +#ifndef VMS + char *pnt; + time_t timeb; + + time (& timeb); + pnt = ctime (&timeb); + pnt[3] = 0; + pnt[7] = 0; + pnt[10] = 0; + pnt[16] = 0; + pnt[24] = 0; + sprintf ((char *) tbuf, "%2s-%3s-%s %s", + pnt + 8, pnt + 4, pnt + 20, pnt + 11); +#else + struct + { + int Size; + unsigned char *Ptr; + } Descriptor; + Descriptor.Size = 17; + Descriptor.Ptr = tbuf; + SYS$ASCTIM (0, &Descriptor, 0, 0); +#endif /* not VMS */ + + vms_debug2 ((6, "vmstimestring:'%s'\n", tbuf)); + + return tbuf; +} - if (maxlen > EOBJ_S_C_SYMSIZ) - maxlen = EOBJ_S_C_SYMSIZ; +/* Create module name from filename (ie, extract the basename and convert it + in upper cases). Works on both VMS and UNIX pathes. + The result has to be free(). */ - /* Save this for later. */ - new_name = out; +char * +vms_get_module_name (const char *filename, bfd_boolean upcase) +{ + char *fname, *fptr; + const char *fout; + + /* Strip VMS path. */ + fout = strrchr (filename, ']'); + if (fout == NULL) + fout = strchr (filename, ':'); + if (fout != NULL) + fout++; + else + fout = filename; - /* We may need to truncate the symbol, save the hash for later. */ - in_len = strlen (in); + /* Strip UNIX path. */ + fptr = strrchr (fout, '/'); + if (fptr != NULL) + fout = fptr + 1; - result = (in_len > maxlen) ? hash_string (in) : 0; + fname = strdup (fout); - old_name = in; + /* Strip suffix. */ + fptr = strrchr (fname, '.'); + if (fptr != 0) + *fptr = 0; - /* Do the length checking. */ - if (in_len <= maxlen) - i = in_len; - else + /* Convert to upper case and truncate at 31 characters. + (VMS object file format restricts module name length to 31). */ + fptr = fname; + for (fptr = fname; *fptr != 0; fptr++) { - if (PRIV (flag_hash_long_names)) - i = maxlen-9; - else - i = maxlen; + if (*fptr == ';' || (fptr - fname) >= 31) + { + *fptr = 0; + break; + } + if (upcase) + *fptr = TOUPPER (*fptr); } + return fname; +} - strncpy (out, in, (size_t) i); - in += i; - out += i; +/* Compared to usual UNIX time_t, VMS time has less limits: + - 64 bit (63 bits in fact as the MSB must be 0) + - 100ns granularity + - epoch is Nov 17, 1858. + Here has the constants and the routines used to convert VMS from/to UNIX time. + The conversion routines don't assume 64 bits arithmetic. - if ((in_len > maxlen) - && PRIV (flag_hash_long_names)) - sprintf (out, "_%08lx", result); - else - *out = 0; + Here we assume that the definition of time_t is the UNIX one, ie integer + type, expressing seconds since the epoch. */ -#if VMS_DEBUG - vms_debug (4, "--> [%d]\"%s\"\n", strlen (outbuf), outbuf); -#endif +/* UNIX time granularity for VMS, ie 1s / 100ns. */ +#define VMS_TIME_FACTOR 10000000 - if (in_len > maxlen - && PRIV (flag_hash_long_names) - && PRIV (flag_show_after_trunc)) - printf (_("Symbol %s replaced by %s\n"), old_name, new_name); +/* Number of seconds since VMS epoch of the UNIX epoch. */ +#define VMS_TIME_OFFSET 3506716800U - return outbuf; -} - -/* Allocate and initialize a new symbol. */ +/* Convert a VMS time to a unix time. */ -static asymbol * -new_symbol (bfd * abfd, char *name) +time_t +vms_time_to_time_t (unsigned int hi, unsigned int lo) { - asymbol *symbol; + unsigned int tmp; + unsigned int rlo; + int i; + time_t res; -#if VMS_DEBUG - _bfd_vms_debug (7, "new_symbol %s\n", name); -#endif + /* First convert to seconds. */ + tmp = hi % VMS_TIME_FACTOR; + hi = hi / VMS_TIME_FACTOR; + rlo = 0; + for (i = 0; i < 4; i++) + { + tmp = (tmp << 8) | (lo >> 24); + lo <<= 8; - symbol = bfd_make_empty_symbol (abfd); - if (symbol == 0) - return symbol; - symbol->name = name; - symbol->section = (asection *)(unsigned long)-1; + rlo = (rlo << 8) | (tmp / VMS_TIME_FACTOR); + tmp %= VMS_TIME_FACTOR; + } + lo = rlo; + + /* Return 0 in case of overflow. */ + if (hi > 1 + || (hi == 1 && lo >= VMS_TIME_OFFSET)) + return 0; + + /* Return 0 in case of underflow. */ + if (hi == 0 && lo < VMS_TIME_OFFSET) + return 0; - return symbol; + res = lo - VMS_TIME_OFFSET; + if (res <= 0) + return 0; + return res; } -/* Allocate and enter a new private symbol. */ +/* Convert a time_t to a VMS time. */ -vms_symbol_entry * -_bfd_vms_enter_symbol (bfd * abfd, char *name) +void +vms_time_t_to_vms_time (time_t ut, unsigned int *hi, unsigned int *lo) { - vms_symbol_entry *entry; + unsigned short val[4]; + unsigned short tmp[4]; + unsigned int carry; + int i; -#if VMS_DEBUG - _bfd_vms_debug (6, "_bfd_vms_enter_symbol %s\n", name); -#endif + /* Put into val. */ + val[0] = ut & 0xffff; + val[1] = (ut >> 16) & 0xffff; + val[2] = sizeof (ut) > 4 ? (ut >> 32) & 0xffff : 0; + val[3] = sizeof (ut) > 4 ? (ut >> 48) & 0xffff : 0; + + /* Add offset. */ + tmp[0] = VMS_TIME_OFFSET & 0xffff; + tmp[1] = VMS_TIME_OFFSET >> 16; + tmp[2] = 0; + tmp[3] = 0; + carry = 0; + for (i = 0; i < 4; i++) + { + carry += tmp[i] + val[i]; + val[i] = carry & 0xffff; + carry = carry >> 16; + } - entry = (vms_symbol_entry *) - bfd_hash_lookup (PRIV (vms_symbol_table), name, FALSE, FALSE); - if (entry == 0) + /* Multiply by factor, well first by 10000 and then by 1000. */ + carry = 0; + for (i = 0; i < 4; i++) { -#if VMS_DEBUG - _bfd_vms_debug (8, "creating hash entry for %s\n", name); -#endif - entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table), - name, TRUE, FALSE); - if (entry != 0) - { - asymbol *symbol; - symbol = new_symbol (abfd, name); - if (symbol != 0) - { - entry->symbol = symbol; - PRIV (gsd_sym_count)++; - abfd->symcount++; - } - else - entry = 0; - } - else - (*_bfd_error_handler) (_("failed to enter %s"), name); + carry += val[i] * 10000; + val[i] = carry & 0xffff; + carry = carry >> 16; } - else + carry = 0; + for (i = 0; i < 4; i++) { -#if VMS_DEBUG - _bfd_vms_debug (8, "found hash entry for %s\n", name); -#endif + carry += val[i] * 1000; + val[i] = carry & 0xffff; + carry = carry >> 16; } -#if VMS_DEBUG - _bfd_vms_debug (7, "-> entry %p, entry->symbol %p\n", entry, entry->symbol); + /* Write the result. */ + *lo = val[0] | (val[1] << 16); + *hi = val[2] | (val[3] << 16); +} + +/* Convert a raw (stored in a buffer) VMS time to a unix time. */ + +time_t +vms_rawtime_to_time_t (unsigned char *buf) +{ + unsigned int hi = bfd_getl32 (buf + 4); + unsigned int lo = bfd_getl32 (buf + 0); + + return vms_time_to_time_t (hi, lo); +} + +void +vms_get_time (unsigned int *hi, unsigned int *lo) +{ +#ifdef VMS + struct _generic_64 t; + + sys$gettim (&t); + *lo = t.gen64$q_quadword; + *hi = t.gen64$q_quadword >> 32; +#else + time_t t; + + time (&t); + vms_time_t_to_vms_time (t, hi, lo); #endif - return entry; +} + +/* Get the current time into a raw buffer BUF. */ + +void +vms_raw_get_time (unsigned char *buf) +{ + unsigned int hi, lo; + + vms_get_time (&hi, &lo); + bfd_putl32 (lo, buf + 0); + bfd_putl32 (hi, buf + 4); }