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