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