vms-misc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. /* vms-misc.c -- BFD back-end for VMS/VAX (openVMS/VAX) and
  2. EVAX (openVMS/Alpha) files.
  3. Copyright (C) 1996-2015 Free Software Foundation, Inc.
  4. Miscellaneous functions.
  5. Written by Klaus K"ampf (kkaempf@rmi.de)
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  17. MA 02110-1301, USA. */
  18. #if __STDC__
  19. #include <stdarg.h>
  20. #endif
  21. #include "sysdep.h"
  22. #include "bfd.h"
  23. #include "bfdlink.h"
  24. #include "libbfd.h"
  25. #include "safe-ctype.h"
  26. #ifdef VMS
  27. #define __NEW_STARLET
  28. #include <rms.h>
  29. #include <unixlib.h>
  30. #include <gen64def.h>
  31. #include <starlet.h>
  32. #define RME$C_SETRFM 0x00000001
  33. #include <unistd.h>
  34. #endif
  35. #include <time.h>
  36. #include "vms.h"
  37. #include "vms/emh.h"
  38. #if VMS_DEBUG
  39. /* Debug functions. */
  40. /* Debug function for all vms extensions evaluates environment
  41. variable VMS_DEBUG for a numerical value on the first call all
  42. error levels below this value are printed:
  43. Levels:
  44. 1 toplevel bfd calls (functions from the bfd vector)
  45. 2 functions called by bfd calls
  46. ...
  47. 9 almost everything
  48. Level is also indentation level. Indentation is performed
  49. if level > 0. */
  50. void
  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. if (min_level == -1)
  59. {
  60. if ((eptr = getenv ("VMS_DEBUG")) != NULL)
  61. {
  62. min_level = atoi (eptr);
  63. output = stderr;
  64. }
  65. else
  66. min_level = 0;
  67. }
  68. if (output == NULL)
  69. return;
  70. if (abslvl > min_level)
  71. return;
  72. while (--level > 0)
  73. fprintf (output, " ");
  74. va_start (args, format);
  75. vfprintf (output, format, args);
  76. fflush (output);
  77. va_end (args);
  78. }
  79. /* A debug function
  80. hex dump 'size' bytes starting at 'ptr'. */
  81. void
  82. _bfd_hexdump (int level, unsigned char *ptr, int size, int offset)
  83. {
  84. unsigned char *lptr = ptr;
  85. int count = 0;
  86. long start = offset;
  87. while (size-- > 0)
  88. {
  89. if ((count % 16) == 0)
  90. vms_debug (level, "%08lx:", start);
  91. vms_debug (-level, " %02x", *ptr++);
  92. count++;
  93. start++;
  94. if (size == 0)
  95. {
  96. while ((count % 16) != 0)
  97. {
  98. vms_debug (-level, " ");
  99. count++;
  100. }
  101. }
  102. if ((count % 16) == 0)
  103. {
  104. vms_debug (-level, " ");
  105. while (lptr < ptr)
  106. {
  107. vms_debug (-level, "%c", (*lptr < 32) ? '.' : *lptr);
  108. lptr++;
  109. }
  110. vms_debug (-level, "\n");
  111. }
  112. }
  113. if ((count % 16) != 0)
  114. vms_debug (-level, "\n");
  115. }
  116. #endif
  117. /* Copy sized string (string with fixed size) to new allocated area
  118. size is string size (size of record) */
  119. char *
  120. _bfd_vms_save_sized_string (unsigned char *str, int size)
  121. {
  122. char *newstr = bfd_malloc ((bfd_size_type) size + 1);
  123. if (newstr == NULL)
  124. return NULL;
  125. memcpy (newstr, (char *) str, (size_t) size);
  126. newstr[size] = 0;
  127. return newstr;
  128. }
  129. /* Copy counted string (string with size at first byte) to new allocated area
  130. ptr points to size byte on entry */
  131. char *
  132. _bfd_vms_save_counted_string (unsigned char *ptr)
  133. {
  134. int len = *ptr++;
  135. return _bfd_vms_save_sized_string (ptr, len);
  136. }
  137. /* Object output routines. */
  138. /* Begin new record.
  139. Write 2 bytes rectype and 2 bytes record length. */
  140. void
  141. _bfd_vms_output_begin (struct vms_rec_wr *recwr, int rectype)
  142. {
  143. vms_debug2 ((6, "_bfd_vms_output_begin (type %d)\n", rectype));
  144. /* Record must have been closed. */
  145. BFD_ASSERT (recwr->size == 0);
  146. _bfd_vms_output_short (recwr, (unsigned int) rectype);
  147. /* Placeholder for length. */
  148. _bfd_vms_output_short (recwr, 0);
  149. }
  150. /* Begin new sub-record.
  151. Write 2 bytes rectype, and 2 bytes record length. */
  152. void
  153. _bfd_vms_output_begin_subrec (struct vms_rec_wr *recwr, int rectype)
  154. {
  155. vms_debug2 ((6, "_bfd_vms_output_begin_subrec (type %d)\n", rectype));
  156. /* Subrecord must have been closed. */
  157. BFD_ASSERT (recwr->subrec_offset == 0);
  158. /* Save start of subrecord offset. */
  159. recwr->subrec_offset = recwr->size;
  160. /* Subrecord type. */
  161. _bfd_vms_output_short (recwr, (unsigned int) rectype);
  162. /* Placeholder for length. */
  163. _bfd_vms_output_short (recwr, 0);
  164. }
  165. /* Set record/subrecord alignment. */
  166. void
  167. _bfd_vms_output_alignment (struct vms_rec_wr *recwr, int alignto)
  168. {
  169. vms_debug2 ((6, "_bfd_vms_output_alignment (%d)\n", alignto));
  170. recwr->align = alignto;
  171. }
  172. /* Align the size of the current record (whose length is LENGTH).
  173. Warning: this obviously changes the record (and the possible subrecord)
  174. length. */
  175. static void
  176. _bfd_vms_output_align (struct vms_rec_wr *recwr, unsigned int length)
  177. {
  178. unsigned int real_size = recwr->size;
  179. unsigned int aligncount;
  180. /* Pad with 0 if alignment is required. */
  181. aligncount = (recwr->align - (length % recwr->align)) % recwr->align;
  182. vms_debug2 ((6, "align: adding %d bytes\n", aligncount));
  183. while (aligncount-- > 0)
  184. recwr->buf[real_size++] = 0;
  185. recwr->size = real_size;
  186. }
  187. /* Ends current sub-record. Set length field. */
  188. void
  189. _bfd_vms_output_end_subrec (struct vms_rec_wr *recwr)
  190. {
  191. int real_size = recwr->size;
  192. int length;
  193. /* Subrecord must be open. */
  194. BFD_ASSERT (recwr->subrec_offset != 0);
  195. length = real_size - recwr->subrec_offset;
  196. if (length == 0)
  197. return;
  198. _bfd_vms_output_align (recwr, length);
  199. /* Put length to buffer. */
  200. bfd_putl16 ((bfd_vma) (recwr->size - recwr->subrec_offset),
  201. recwr->buf + recwr->subrec_offset + 2);
  202. /* Close the subrecord. */
  203. recwr->subrec_offset = 0;
  204. }
  205. /* Ends current record (and write it). */
  206. void
  207. _bfd_vms_output_end (bfd *abfd, struct vms_rec_wr *recwr)
  208. {
  209. vms_debug2 ((6, "_bfd_vms_output_end (size %u)\n", recwr->size));
  210. /* Subrecord must have been closed. */
  211. BFD_ASSERT (recwr->subrec_offset == 0);
  212. if (recwr->size == 0)
  213. return;
  214. _bfd_vms_output_align (recwr, recwr->size);
  215. /* Write the length word. */
  216. bfd_putl16 ((bfd_vma) recwr->size, recwr->buf + 2);
  217. /* File is open in undefined (UDF) format on VMS, but ultimately will be
  218. converted to variable length (VAR) format. VAR format has a length
  219. word first which must be explicitly output in UDF format. */
  220. /* So, first the length word. */
  221. bfd_bwrite (recwr->buf + 2, 2, abfd);
  222. /* Align. */
  223. if (recwr->size & 1)
  224. recwr->buf[recwr->size++] = 0;
  225. /* Then the record. */
  226. bfd_bwrite (recwr->buf, (size_t) recwr->size, abfd);
  227. recwr->size = 0;
  228. }
  229. /* Check remaining buffer size. Return what's left. */
  230. int
  231. _bfd_vms_output_check (struct vms_rec_wr *recwr, int size)
  232. {
  233. vms_debug2 ((6, "_bfd_vms_output_check (%d)\n", size));
  234. return (MAX_OUTREC_SIZE - (recwr->size + size + MIN_OUTREC_LUFT));
  235. }
  236. /* Output byte (8 bit) value. */
  237. void
  238. _bfd_vms_output_byte (struct vms_rec_wr *recwr, unsigned int value)
  239. {
  240. vms_debug2 ((6, "_bfd_vms_output_byte (%02x)\n", value));
  241. *(recwr->buf + recwr->size) = value;
  242. recwr->size += 1;
  243. }
  244. /* Output short (16 bit) value. */
  245. void
  246. _bfd_vms_output_short (struct vms_rec_wr *recwr, unsigned int value)
  247. {
  248. vms_debug2 ((6, "_bfd_vms_output_short (%04x)\n", value));
  249. bfd_putl16 ((bfd_vma) value & 0xffff, recwr->buf + recwr->size);
  250. recwr->size += 2;
  251. }
  252. /* Output long (32 bit) value. */
  253. void
  254. _bfd_vms_output_long (struct vms_rec_wr *recwr, unsigned long value)
  255. {
  256. vms_debug2 ((6, "_bfd_vms_output_long (%08lx)\n", value));
  257. bfd_putl32 ((bfd_vma) value, recwr->buf + recwr->size);
  258. recwr->size += 4;
  259. }
  260. /* Output quad (64 bit) value. */
  261. void
  262. _bfd_vms_output_quad (struct vms_rec_wr *recwr, bfd_vma value)
  263. {
  264. vms_debug2 ((6, "_bfd_vms_output_quad (%08lx)\n", (unsigned long)value));
  265. bfd_putl64 (value, recwr->buf + recwr->size);
  266. recwr->size += 8;
  267. }
  268. /* Output c-string as counted string. */
  269. void
  270. _bfd_vms_output_counted (struct vms_rec_wr *recwr, const char *value)
  271. {
  272. int len;
  273. vms_debug2 ((6, "_bfd_vms_output_counted (%s)\n", value));
  274. len = strlen (value);
  275. if (len == 0)
  276. {
  277. (*_bfd_error_handler) (_("_bfd_vms_output_counted called with zero bytes"));
  278. return;
  279. }
  280. if (len > 255)
  281. {
  282. (*_bfd_error_handler) (_("_bfd_vms_output_counted called with too many bytes"));
  283. return;
  284. }
  285. _bfd_vms_output_byte (recwr, (unsigned int) len & 0xff);
  286. _bfd_vms_output_dump (recwr, (const unsigned char *)value, len);
  287. }
  288. /* Output character area. */
  289. void
  290. _bfd_vms_output_dump (struct vms_rec_wr *recwr, const unsigned char *data, int len)
  291. {
  292. vms_debug2 ((6, "_bfd_vms_output_dump (%d)\n", len));
  293. if (len == 0)
  294. return;
  295. memcpy (recwr->buf + recwr->size, data, (size_t) len);
  296. recwr->size += len;
  297. }
  298. /* Output count bytes of value. */
  299. void
  300. _bfd_vms_output_fill (struct vms_rec_wr *recwr, int value, int count)
  301. {
  302. vms_debug2 ((6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count));
  303. if (count == 0)
  304. return;
  305. memset (recwr->buf + recwr->size, value, (size_t) count);
  306. recwr->size += count;
  307. }
  308. #ifdef VMS
  309. /* Convert the file to variable record length format. This is done
  310. using undocumented system call sys$modify().
  311. Pure VMS version. */
  312. static void
  313. vms_convert_to_var (char * vms_filename)
  314. {
  315. struct FAB fab = cc$rms_fab;
  316. fab.fab$l_fna = vms_filename;
  317. fab.fab$b_fns = strlen (vms_filename);
  318. fab.fab$b_fac = FAB$M_PUT;
  319. fab.fab$l_fop = FAB$M_ESC;
  320. fab.fab$l_ctx = RME$C_SETRFM;
  321. sys$open (&fab);
  322. fab.fab$b_rfm = FAB$C_VAR;
  323. sys$modify (&fab);
  324. sys$close (&fab);
  325. }
  326. static int
  327. vms_convert_to_var_1 (char *filename, int type)
  328. {
  329. if (type != DECC$K_FILE)
  330. return FALSE;
  331. vms_convert_to_var (filename);
  332. return TRUE;
  333. }
  334. /* Convert the file to variable record length format. This is done
  335. using undocumented system call sys$modify().
  336. Unix filename version. */
  337. int
  338. _bfd_vms_convert_to_var_unix_filename (const char *unix_filename)
  339. {
  340. if (decc$to_vms (unix_filename, &vms_convert_to_var_1, 0, 1) != 1)
  341. return FALSE;
  342. return TRUE;
  343. }
  344. #endif /* VMS */
  345. /* Manufacture a VMS like time on a unix based system.
  346. stolen from obj-vms.c. */
  347. unsigned char *
  348. get_vms_time_string (void)
  349. {
  350. static unsigned char tbuf[18];
  351. #ifndef VMS
  352. char *pnt;
  353. time_t timeb;
  354. time (& timeb);
  355. pnt = ctime (&timeb);
  356. pnt[3] = 0;
  357. pnt[7] = 0;
  358. pnt[10] = 0;
  359. pnt[16] = 0;
  360. pnt[24] = 0;
  361. sprintf ((char *) tbuf, "%2s-%3s-%s %s",
  362. pnt + 8, pnt + 4, pnt + 20, pnt + 11);
  363. #else
  364. struct
  365. {
  366. int Size;
  367. unsigned char *Ptr;
  368. } Descriptor;
  369. Descriptor.Size = 17;
  370. Descriptor.Ptr = tbuf;
  371. SYS$ASCTIM (0, &Descriptor, 0, 0);
  372. #endif /* not VMS */
  373. vms_debug2 ((6, "vmstimestring:'%s'\n", tbuf));
  374. return tbuf;
  375. }
  376. /* Create module name from filename (ie, extract the basename and convert it
  377. in upper cases). Works on both VMS and UNIX pathes.
  378. The result has to be free(). */
  379. char *
  380. vms_get_module_name (const char *filename, bfd_boolean upcase)
  381. {
  382. char *fname, *fptr;
  383. const char *fout;
  384. /* Strip VMS path. */
  385. fout = strrchr (filename, ']');
  386. if (fout == NULL)
  387. fout = strchr (filename, ':');
  388. if (fout != NULL)
  389. fout++;
  390. else
  391. fout = filename;
  392. /* Strip UNIX path. */
  393. fptr = strrchr (fout, '/');
  394. if (fptr != NULL)
  395. fout = fptr + 1;
  396. fname = strdup (fout);
  397. /* Strip suffix. */
  398. fptr = strrchr (fname, '.');
  399. if (fptr != 0)
  400. *fptr = 0;
  401. /* Convert to upper case and truncate at 31 characters.
  402. (VMS object file format restricts module name length to 31). */
  403. fptr = fname;
  404. for (fptr = fname; *fptr != 0; fptr++)
  405. {
  406. if (*fptr == ';' || (fptr - fname) >= 31)
  407. {
  408. *fptr = 0;
  409. break;
  410. }
  411. if (upcase)
  412. *fptr = TOUPPER (*fptr);
  413. }
  414. return fname;
  415. }
  416. /* Compared to usual UNIX time_t, VMS time has less limits:
  417. - 64 bit (63 bits in fact as the MSB must be 0)
  418. - 100ns granularity
  419. - epoch is Nov 17, 1858.
  420. Here has the constants and the routines used to convert VMS from/to UNIX time.
  421. The conversion routines don't assume 64 bits arithmetic.
  422. Here we assume that the definition of time_t is the UNIX one, ie integer
  423. type, expressing seconds since the epoch. */
  424. /* UNIX time granularity for VMS, ie 1s / 100ns. */
  425. #define VMS_TIME_FACTOR 10000000
  426. /* Number of seconds since VMS epoch of the UNIX epoch. */
  427. #define VMS_TIME_OFFSET 3506716800U
  428. /* Convert a VMS time to a unix time. */
  429. time_t
  430. vms_time_to_time_t (unsigned int hi, unsigned int lo)
  431. {
  432. unsigned int tmp;
  433. unsigned int rlo;
  434. int i;
  435. time_t res;
  436. /* First convert to seconds. */
  437. tmp = hi % VMS_TIME_FACTOR;
  438. hi = hi / VMS_TIME_FACTOR;
  439. rlo = 0;
  440. for (i = 0; i < 4; i++)
  441. {
  442. tmp = (tmp << 8) | (lo >> 24);
  443. lo <<= 8;
  444. rlo = (rlo << 8) | (tmp / VMS_TIME_FACTOR);
  445. tmp %= VMS_TIME_FACTOR;
  446. }
  447. lo = rlo;
  448. /* Return 0 in case of overflow. */
  449. if (hi > 1
  450. || (hi == 1 && lo >= VMS_TIME_OFFSET))
  451. return 0;
  452. /* Return 0 in case of underflow. */
  453. if (hi == 0 && lo < VMS_TIME_OFFSET)
  454. return 0;
  455. res = lo - VMS_TIME_OFFSET;
  456. if (res <= 0)
  457. return 0;
  458. return res;
  459. }
  460. /* Convert a time_t to a VMS time. */
  461. void
  462. vms_time_t_to_vms_time (time_t ut, unsigned int *hi, unsigned int *lo)
  463. {
  464. unsigned short val[4];
  465. unsigned short tmp[4];
  466. unsigned int carry;
  467. int i;
  468. /* Put into val. */
  469. val[0] = ut & 0xffff;
  470. val[1] = (ut >> 16) & 0xffff;
  471. val[2] = sizeof (ut) > 4 ? (ut >> 32) & 0xffff : 0;
  472. val[3] = sizeof (ut) > 4 ? (ut >> 48) & 0xffff : 0;
  473. /* Add offset. */
  474. tmp[0] = VMS_TIME_OFFSET & 0xffff;
  475. tmp[1] = VMS_TIME_OFFSET >> 16;
  476. tmp[2] = 0;
  477. tmp[3] = 0;
  478. carry = 0;
  479. for (i = 0; i < 4; i++)
  480. {
  481. carry += tmp[i] + val[i];
  482. val[i] = carry & 0xffff;
  483. carry = carry >> 16;
  484. }
  485. /* Multiply by factor, well first by 10000 and then by 1000. */
  486. carry = 0;
  487. for (i = 0; i < 4; i++)
  488. {
  489. carry += val[i] * 10000;
  490. val[i] = carry & 0xffff;
  491. carry = carry >> 16;
  492. }
  493. carry = 0;
  494. for (i = 0; i < 4; i++)
  495. {
  496. carry += val[i] * 1000;
  497. val[i] = carry & 0xffff;
  498. carry = carry >> 16;
  499. }
  500. /* Write the result. */
  501. *lo = val[0] | (val[1] << 16);
  502. *hi = val[2] | (val[3] << 16);
  503. }
  504. /* Convert a raw (stored in a buffer) VMS time to a unix time. */
  505. time_t
  506. vms_rawtime_to_time_t (unsigned char *buf)
  507. {
  508. unsigned int hi = bfd_getl32 (buf + 4);
  509. unsigned int lo = bfd_getl32 (buf + 0);
  510. return vms_time_to_time_t (hi, lo);
  511. }
  512. void
  513. vms_get_time (unsigned int *hi, unsigned int *lo)
  514. {
  515. #ifdef VMS
  516. struct _generic_64 t;
  517. sys$gettim (&t);
  518. *lo = t.gen64$q_quadword;
  519. *hi = t.gen64$q_quadword >> 32;
  520. #else
  521. time_t t;
  522. time (&t);
  523. vms_time_t_to_vms_time (t, hi, lo);
  524. #endif
  525. }
  526. /* Get the current time into a raw buffer BUF. */
  527. void
  528. vms_raw_get_time (unsigned char *buf)
  529. {
  530. unsigned int hi, lo;
  531. vms_get_time (&hi, &lo);
  532. bfd_putl32 (lo, buf + 0);
  533. bfd_putl32 (hi, buf + 4);
  534. }