1/* vms-hdr.c -- BFD back-end for VMS/VAX (openVMS/VAX) and
2   EVAX (openVMS/Alpha) files.
3   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006
4   Free Software Foundation, Inc.
5
6   HDR record handling functions
7   EMH record handling functions
8   and
9   EOM record handling functions
10   EEOM record handling functions
11
12   Written by Klaus K"ampf (kkaempf@rmi.de)
13
14   This program is free software; you can redistribute it and/or modify
15   it under the terms of the GNU General Public License as published by
16   the Free Software Foundation; either version 2 of the License, or
17   (at your option) any later version.
18
19   This program is distributed in the hope that it will be useful,
20   but WITHOUT ANY WARRANTY; without even the implied warranty of
21   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22   GNU General Public License for more details.
23
24   You should have received a copy of the GNU General Public License
25   along with this program; if not, write to the Free Software
26   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
27
28#include "bfd.h"
29#include "bfdver.h"
30#include "sysdep.h"
31#include "bfdlink.h"
32#include "safe-ctype.h"
33#include "libbfd.h"
34
35#include "vms.h"
36
37#ifdef HAVE_ALLOCA_H
38#include <alloca.h>
39#endif
40
41/* Read & process emh record
42   return 0 on success, -1 on error.  */
43
44int
45_bfd_vms_slurp_hdr (bfd *abfd, int objtype)
46{
47  unsigned char *ptr;
48  unsigned char *vms_rec;
49  int subtype;
50
51  vms_rec = PRIV(vms_rec);
52
53#if VMS_DEBUG
54  vms_debug(2, "HDR/EMH\n");
55#endif
56
57  switch (objtype)
58    {
59    case OBJ_S_C_HDR:
60      subtype = vms_rec[1];
61      break;
62    case EOBJ_S_C_EMH:
63      subtype = bfd_getl16 (vms_rec + 4) + EVAX_OFFSET;
64      break;
65    default:
66      subtype = -1;
67    }
68
69#if VMS_DEBUG
70  vms_debug(3, "subtype %d\n", subtype);
71#endif
72
73  switch (subtype)
74    {
75    case MHD_S_C_MHD:
76      /* Module header.  */
77      PRIV (hdr_data).hdr_b_strlvl = vms_rec[2];
78      PRIV (hdr_data).hdr_l_recsiz = bfd_getl16 (vms_rec + 3);
79      PRIV (hdr_data).hdr_t_name = _bfd_vms_save_counted_string (vms_rec + 5);
80      ptr = vms_rec + 5 + vms_rec[5] + 1;
81      PRIV (hdr_data).hdr_t_version = _bfd_vms_save_counted_string (ptr);
82      ptr += *ptr + 1;
83      PRIV (hdr_data).hdr_t_date = _bfd_vms_save_sized_string (ptr, 17);
84      break;
85
86    case MHD_S_C_LNM:
87      PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 2));
88      break;
89
90    case MHD_S_C_SRC:
91      PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 2));
92      break;
93
94    case MHD_S_C_TTL:
95      PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 2));
96      break;
97
98    case EMH_S_C_MHD + EVAX_OFFSET:
99      /* Module header.  */
100      PRIV (hdr_data).hdr_b_strlvl = vms_rec[6];
101      PRIV (hdr_data).hdr_l_arch1  = bfd_getl32 (vms_rec + 8);
102      PRIV (hdr_data).hdr_l_arch2  = bfd_getl32 (vms_rec + 12);
103      PRIV (hdr_data).hdr_l_recsiz = bfd_getl32 (vms_rec + 16);
104      PRIV (hdr_data).hdr_t_name   = _bfd_vms_save_counted_string (vms_rec + 20);
105      ptr = vms_rec + 20 + vms_rec[20] + 1;
106      PRIV (hdr_data).hdr_t_version =_bfd_vms_save_counted_string (ptr);
107      ptr += *ptr + 1;
108      PRIV (hdr_data).hdr_t_date = _bfd_vms_save_sized_string (ptr, 17);
109      break;
110
111    case EMH_S_C_LNM + EVAX_OFFSET:
112      PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 6));
113      break;
114
115    case EMH_S_C_SRC + EVAX_OFFSET:
116      PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 6));
117      break;
118
119    case EMH_S_C_TTL + EVAX_OFFSET:
120      PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 6));
121      break;
122
123    case MHD_S_C_CPR:
124    case MHD_S_C_MTC:
125    case MHD_S_C_GTX:
126    case EMH_S_C_CPR + EVAX_OFFSET:
127    case EMH_S_C_MTC + EVAX_OFFSET:
128    case EMH_S_C_GTX + EVAX_OFFSET:
129      break;
130
131    default:
132      bfd_set_error (bfd_error_wrong_format);
133      return -1;
134    }
135
136  return 0;
137}
138
139/* Output routines.  */
140
141/* Manufacture a VMS like time on a unix based system.
142   stolen from obj-vms.c.  */
143
144static unsigned char *
145get_vms_time_string (void)
146{
147  static unsigned char tbuf[18];
148#ifndef VMS
149#include <time.h>
150
151  char *pnt;
152  time_t timeb;
153
154  time (& timeb);
155  pnt = ctime (&timeb);
156  pnt[3] = 0;
157  pnt[7] = 0;
158  pnt[10] = 0;
159  pnt[16] = 0;
160  pnt[24] = 0;
161  sprintf ((char *) tbuf, "%2s-%3s-%s %s",
162	   pnt + 8, pnt + 4, pnt + 20, pnt + 11);
163#else
164#include <starlet.h>
165  struct
166  {
167    int Size;
168    unsigned char *Ptr;
169  } Descriptor;
170  Descriptor.Size = 17;
171  Descriptor.Ptr = tbuf;
172  SYS$ASCTIM (0, &Descriptor, 0, 0);
173#endif /* not VMS */
174
175#if VMS_DEBUG
176  vms_debug (6, "vmstimestring:'%s'\n", tbuf);
177#endif
178
179  return tbuf;
180}
181
182/* Write object header for bfd abfd.  */
183
184int
185_bfd_vms_write_hdr (bfd *abfd, int objtype)
186{
187  asymbol *symbol;
188  unsigned int symnum;
189  int had_case = 0;
190  int had_file = 0;
191
192#if VMS_DEBUG
193  vms_debug (2, "vms_write_hdr (%p)\n", abfd);
194#endif
195
196  _bfd_vms_output_alignment (abfd, 2);
197
198  /* MHD.  */
199  if (objtype != OBJ_S_C_HDR)
200    {
201      _bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_MHD);
202      _bfd_vms_output_short (abfd, EOBJ_S_C_STRLVL);
203      _bfd_vms_output_long (abfd, 0);
204      _bfd_vms_output_long (abfd, 0);
205      _bfd_vms_output_long (abfd, MAX_OUTREC_SIZE);
206    }
207
208  if (bfd_get_filename (abfd) != 0)
209    {
210      /* Strip path and suffix information.  */
211      char *fname, *fout, *fptr;
212
213      fptr = bfd_get_filename (abfd);
214      fname = alloca (strlen (fptr) + 1);
215      strcpy (fname, fptr);
216      fout = strrchr (fname, ']');
217      if (fout == 0)
218	fout = strchr (fname, ':');
219      if (fout != 0)
220	fout++;
221      else
222	fout = fname;
223
224      /* Strip .obj suffix.  */
225      fptr = strrchr (fname, '.');
226      if ((fptr != 0)
227	  && (strcasecmp (fptr, ".OBJ") == 0))
228	*fptr = 0;
229
230      fptr = fout;
231      while (*fptr != 0)
232	{
233	  *fptr = TOUPPER (*fptr);
234	  fptr++;
235	  if ((*fptr == ';')
236	     || ((fptr - fout) > 31))
237	    *fptr = 0;
238	}
239      _bfd_vms_output_counted (abfd, fout);
240    }
241  else
242    _bfd_vms_output_counted (abfd, "NONAME");
243
244  _bfd_vms_output_counted (abfd, BFD_VERSION_STRING);
245  _bfd_vms_output_dump (abfd, get_vms_time_string (), 17);
246  _bfd_vms_output_fill (abfd, 0, 17);
247  _bfd_vms_output_flush (abfd);
248
249  /* LMN.  */
250  _bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_LNM);
251  _bfd_vms_output_dump (abfd, (unsigned char *) STRING_COMMA_LEN ("GAS proGIS"));
252  _bfd_vms_output_flush (abfd);
253
254  /* SRC.  */
255  _bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_SRC);
256
257  for (symnum = 0; symnum < abfd->symcount; symnum++)
258    {
259      symbol = abfd->outsymbols[symnum];
260
261      if (symbol->flags & BSF_FILE)
262	{
263	  if (CONST_STRNEQ ((char *)symbol->name, "<CASE:"))
264	    {
265	      PRIV (flag_hash_long_names) = symbol->name[6] - '0';
266	      PRIV (flag_show_after_trunc) = symbol->name[7] - '0';
267
268	      if (had_file)
269		break;
270	      had_case = 1;
271	      continue;
272	    }
273
274	  _bfd_vms_output_dump (abfd, (unsigned char *) symbol->name,
275				(int) strlen (symbol->name));
276	  if (had_case)
277	    break;
278	  had_file = 1;
279	}
280    }
281
282  if (symnum == abfd->symcount)
283    _bfd_vms_output_dump (abfd, (unsigned char *) STRING_COMMA_LEN ("noname"));
284
285  _bfd_vms_output_flush (abfd);
286
287  /* TTL.  */
288  _bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_TTL);
289  _bfd_vms_output_dump (abfd, (unsigned char *) STRING_COMMA_LEN ("TTL"));
290  _bfd_vms_output_flush (abfd);
291
292  /* CPR.  */
293  _bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_CPR);
294  _bfd_vms_output_dump (abfd,
295			 (unsigned char *)"GNU BFD ported by Klaus K�mpf 1994-1996",
296			 39);
297  _bfd_vms_output_flush (abfd);
298
299  return 0;
300}
301
302/* Process EOM/EEOM record
303   return 0 on success, -1 on error.  */
304
305int
306_bfd_vms_slurp_eom (bfd *abfd, int objtype)
307{
308  unsigned char *vms_rec;
309
310#if VMS_DEBUG
311  vms_debug(2, "EOM/EEOM\n");
312#endif
313
314  vms_rec = PRIV (vms_rec);
315
316  if ((objtype == OBJ_S_C_EOM)
317     || (objtype == OBJ_S_C_EOMW))
318    {
319    }
320  else
321    {
322      PRIV (eom_data).eom_l_total_lps = bfd_getl32 (vms_rec + 4);
323      PRIV (eom_data).eom_b_comcod = *(vms_rec + 8);
324
325      if (PRIV (eom_data).eom_b_comcod > 1)
326	{
327	  (*_bfd_error_handler) (_("Object module NOT error-free !\n"));
328	  bfd_set_error (bfd_error_bad_value);
329	  return -1;
330	}
331      PRIV (eom_data).eom_has_transfer = FALSE;
332      if (PRIV (rec_size) > 10)
333	{
334	   PRIV (eom_data).eom_has_transfer = TRUE;
335	   PRIV (eom_data).eom_b_tfrflg = *(vms_rec + 9);
336	   PRIV (eom_data).eom_l_psindx = bfd_getl32 (vms_rec + 12);
337	   PRIV (eom_data).eom_l_tfradr = bfd_getl32 (vms_rec + 16);
338
339	   abfd->start_address = PRIV (eom_data).eom_l_tfradr;
340	}
341    }
342  return 0;
343}
344
345/* Write eom record for bfd abfd.  */
346
347int
348_bfd_vms_write_eom (bfd *abfd, int objtype)
349{
350#if VMS_DEBUG
351  vms_debug (2, "vms_write_eom (%p, %d)\n", abfd, objtype);
352#endif
353
354  _bfd_vms_output_begin (abfd, objtype, -1);
355  _bfd_vms_output_long (abfd, (unsigned long) (PRIV (vms_linkage_index) >> 1));
356  _bfd_vms_output_byte (abfd, 0);	/* Completion code.  */
357  _bfd_vms_output_byte (abfd, 0);	/* Fill byte.  */
358
359  if (bfd_get_start_address (abfd) != (bfd_vma)-1)
360    {
361      asection *section;
362
363      section = bfd_get_section_by_name (abfd, ".link");
364      if (section == 0)
365	{
366	  bfd_set_error (bfd_error_nonrepresentable_section);
367	  return -1;
368	}
369      _bfd_vms_output_short (abfd, 0);
370      _bfd_vms_output_long (abfd, (unsigned long) (section->index));
371      _bfd_vms_output_long (abfd,
372			     (unsigned long) bfd_get_start_address (abfd));
373      _bfd_vms_output_long (abfd, 0);
374    }
375
376  _bfd_vms_output_end (abfd);
377  return 0;
378}
379