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