-/* 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;
-}
-\f
-/* 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);
-}