vms-misc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. /* vms-misc.c -- BFD back-end for VMS/VAX (openVMS/VAX) and
  2. EVAX (openVMS/Alpha) files.
  3. Copyright (C) 1996-2022 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 (bfd *abfd, unsigned char *str, size_t size)
  121. {
  122. char *newstr;
  123. if (size == (size_t) -1)
  124. {
  125. bfd_set_error (bfd_error_no_memory);
  126. return NULL;
  127. }
  128. newstr = bfd_alloc (abfd, size + 1);
  129. if (newstr == NULL)
  130. return NULL;
  131. memcpy (newstr, str, size);
  132. newstr[size] = 0;
  133. return newstr;
  134. }
  135. /* Copy counted string (string with size at first byte) to new allocated area.
  136. PTR points to size byte on entry. */
  137. char *
  138. _bfd_vms_save_counted_string (bfd *abfd, unsigned char *ptr, size_t maxlen)
  139. {
  140. unsigned int len;
  141. if (maxlen == 0)
  142. return NULL;
  143. len = *ptr++;
  144. if (len > maxlen - 1)
  145. return NULL;
  146. return _bfd_vms_save_sized_string (abfd, ptr, len);
  147. }
  148. /* Object output routines. */
  149. /* Begin new record.
  150. Write 2 bytes rectype and 2 bytes record length. */
  151. void
  152. _bfd_vms_output_begin (struct vms_rec_wr *recwr, int rectype)
  153. {
  154. vms_debug2 ((6, "_bfd_vms_output_begin (type %d)\n", rectype));
  155. /* Record must have been closed. */
  156. BFD_ASSERT (recwr->size == 0);
  157. _bfd_vms_output_short (recwr, (unsigned int) rectype);
  158. /* Placeholder for length. */
  159. _bfd_vms_output_short (recwr, 0);
  160. }
  161. /* Begin new sub-record.
  162. Write 2 bytes rectype, and 2 bytes record length. */
  163. void
  164. _bfd_vms_output_begin_subrec (struct vms_rec_wr *recwr, int rectype)
  165. {
  166. vms_debug2 ((6, "_bfd_vms_output_begin_subrec (type %d)\n", rectype));
  167. /* Subrecord must have been closed. */
  168. BFD_ASSERT (recwr->subrec_offset == 0);
  169. /* Save start of subrecord offset. */
  170. recwr->subrec_offset = recwr->size;
  171. /* Subrecord type. */
  172. _bfd_vms_output_short (recwr, (unsigned int) rectype);
  173. /* Placeholder for length. */
  174. _bfd_vms_output_short (recwr, 0);
  175. }
  176. /* Set record/subrecord alignment. */
  177. void
  178. _bfd_vms_output_alignment (struct vms_rec_wr *recwr, int alignto)
  179. {
  180. vms_debug2 ((6, "_bfd_vms_output_alignment (%d)\n", alignto));
  181. recwr->align = alignto;
  182. }
  183. /* Align the size of the current record (whose length is LENGTH).
  184. Warning: this obviously changes the record (and the possible subrecord)
  185. length. */
  186. static void
  187. _bfd_vms_output_align (struct vms_rec_wr *recwr, unsigned int length)
  188. {
  189. unsigned int real_size = recwr->size;
  190. unsigned int aligncount;
  191. /* Pad with 0 if alignment is required. */
  192. aligncount = (recwr->align - (length % recwr->align)) % recwr->align;
  193. vms_debug2 ((6, "align: adding %d bytes\n", aligncount));
  194. while (aligncount-- > 0)
  195. recwr->buf[real_size++] = 0;
  196. recwr->size = real_size;
  197. }
  198. /* Ends current sub-record. Set length field. */
  199. void
  200. _bfd_vms_output_end_subrec (struct vms_rec_wr *recwr)
  201. {
  202. int real_size = recwr->size;
  203. int length;
  204. /* Subrecord must be open. */
  205. BFD_ASSERT (recwr->subrec_offset != 0);
  206. length = real_size - recwr->subrec_offset;
  207. if (length == 0)
  208. return;
  209. _bfd_vms_output_align (recwr, length);
  210. /* Put length to buffer. */
  211. bfd_putl16 ((bfd_vma) (recwr->size - recwr->subrec_offset),
  212. recwr->buf + recwr->subrec_offset + 2);
  213. /* Close the subrecord. */
  214. recwr->subrec_offset = 0;
  215. }
  216. /* Ends current record (and write it). */
  217. void
  218. _bfd_vms_output_end (bfd *abfd, struct vms_rec_wr *recwr)
  219. {
  220. vms_debug2 ((6, "_bfd_vms_output_end (size %u)\n", recwr->size));
  221. /* Subrecord must have been closed. */
  222. BFD_ASSERT (recwr->subrec_offset == 0);
  223. if (recwr->size == 0)
  224. return;
  225. _bfd_vms_output_align (recwr, recwr->size);
  226. /* Write the length word. */
  227. bfd_putl16 ((bfd_vma) recwr->size, recwr->buf + 2);
  228. /* File is open in undefined (UDF) format on VMS, but ultimately will be
  229. converted to variable length (VAR) format. VAR format has a length
  230. word first which must be explicitly output in UDF format. */
  231. /* So, first the length word. */
  232. bfd_bwrite (recwr->buf + 2, 2, abfd);
  233. /* Align. */
  234. if (recwr->size & 1)
  235. recwr->buf[recwr->size++] = 0;
  236. /* Then the record. */
  237. bfd_bwrite (recwr->buf, (size_t) recwr->size, abfd);
  238. recwr->size = 0;
  239. }
  240. /* Check remaining buffer size. Return what's left. */
  241. int
  242. _bfd_vms_output_check (struct vms_rec_wr *recwr, int size)
  243. {
  244. vms_debug2 ((6, "_bfd_vms_output_check (%d)\n", size));
  245. return (MAX_OUTREC_SIZE - (recwr->size + size + MIN_OUTREC_LUFT));
  246. }
  247. /* Output byte (8 bit) value. */
  248. void
  249. _bfd_vms_output_byte (struct vms_rec_wr *recwr, unsigned int value)
  250. {
  251. vms_debug2 ((6, "_bfd_vms_output_byte (%02x)\n", value));
  252. *(recwr->buf + recwr->size) = value;
  253. recwr->size += 1;
  254. }
  255. /* Output short (16 bit) value. */
  256. void
  257. _bfd_vms_output_short (struct vms_rec_wr *recwr, unsigned int value)
  258. {
  259. vms_debug2 ((6, "_bfd_vms_output_short (%04x)\n", value));
  260. bfd_putl16 ((bfd_vma) value & 0xffff, recwr->buf + recwr->size);
  261. recwr->size += 2;
  262. }
  263. /* Output long (32 bit) value. */
  264. void
  265. _bfd_vms_output_long (struct vms_rec_wr *recwr, unsigned long value)
  266. {
  267. vms_debug2 ((6, "_bfd_vms_output_long (%08lx)\n", value));
  268. bfd_putl32 ((bfd_vma) value, recwr->buf + recwr->size);
  269. recwr->size += 4;
  270. }
  271. /* Output quad (64 bit) value. */
  272. void
  273. _bfd_vms_output_quad (struct vms_rec_wr *recwr, bfd_vma value)
  274. {
  275. vms_debug2 ((6, "_bfd_vms_output_quad (%08lx)\n", (unsigned long)value));
  276. bfd_putl64 (value, recwr->buf + recwr->size);
  277. recwr->size += 8;
  278. }
  279. /* Output c-string as counted string. */
  280. void
  281. _bfd_vms_output_counted (struct vms_rec_wr *recwr, const char *value)
  282. {
  283. int len;
  284. vms_debug2 ((6, "_bfd_vms_output_counted (%s)\n", value));
  285. len = strlen (value);
  286. if (len == 0)
  287. {
  288. _bfd_error_handler (_("_bfd_vms_output_counted called with zero bytes"));
  289. return;
  290. }
  291. if (len > 255)
  292. {
  293. _bfd_error_handler (_("_bfd_vms_output_counted called with too many bytes"));
  294. return;
  295. }
  296. _bfd_vms_output_byte (recwr, (unsigned int) len & 0xff);
  297. _bfd_vms_output_dump (recwr, (const unsigned char *)value, len);
  298. }
  299. /* Output character area. */
  300. void
  301. _bfd_vms_output_dump (struct vms_rec_wr *recwr, const unsigned char *data, int len)
  302. {
  303. vms_debug2 ((6, "_bfd_vms_output_dump (%d)\n", len));
  304. if (len == 0)
  305. return;
  306. memcpy (recwr->buf + recwr->size, data, (size_t) len);
  307. recwr->size += len;
  308. }
  309. /* Output count bytes of value. */
  310. void
  311. _bfd_vms_output_fill (struct vms_rec_wr *recwr, int value, int count)
  312. {
  313. vms_debug2 ((6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count));
  314. if (count == 0)
  315. return;
  316. memset (recwr->buf + recwr->size, value, (size_t) count);
  317. recwr->size += count;
  318. }
  319. #ifdef VMS
  320. /* Convert the file to variable record length format. This is done
  321. using undocumented system call sys$modify().
  322. Pure VMS version. */
  323. static void
  324. vms_convert_to_var (char * vms_filename)
  325. {
  326. struct FAB fab = cc$rms_fab;
  327. fab.fab$l_fna = vms_filename;
  328. fab.fab$b_fns = strlen (vms_filename);
  329. fab.fab$b_fac = FAB$M_PUT;
  330. fab.fab$l_fop = FAB$M_ESC;
  331. fab.fab$l_ctx = RME$C_SETRFM;
  332. sys$open (&fab);
  333. fab.fab$b_rfm = FAB$C_VAR;
  334. sys$modify (&fab);
  335. sys$close (&fab);
  336. }
  337. static int
  338. vms_convert_to_var_1 (char *filename, int type)
  339. {
  340. if (type != DECC$K_FILE)
  341. return false;
  342. vms_convert_to_var (filename);
  343. return true;
  344. }
  345. /* Convert the file to variable record length format. This is done
  346. using undocumented system call sys$modify().
  347. Unix filename version. */
  348. int
  349. _bfd_vms_convert_to_var_unix_filename (const char *unix_filename)
  350. {
  351. if (decc$to_vms (unix_filename, &vms_convert_to_var_1, 0, 1) != 1)
  352. return false;
  353. return true;
  354. }
  355. #endif /* VMS */
  356. /* Manufacture a VMS like time on a unix based system.
  357. stolen from obj-vms.c. */
  358. unsigned char *
  359. get_vms_time_string (unsigned char *tbuf)
  360. {
  361. #ifndef VMS
  362. char *pnt;
  363. time_t timeb;
  364. time (& timeb);
  365. pnt = ctime (&timeb);
  366. pnt[3] = 0;
  367. pnt[7] = 0;
  368. pnt[10] = 0;
  369. pnt[16] = 0;
  370. pnt[24] = 0;
  371. sprintf ((char *) tbuf, "%2s-%3s-%s %s",
  372. pnt + 8, pnt + 4, pnt + 20, pnt + 11);
  373. #else
  374. struct
  375. {
  376. int Size;
  377. unsigned char *Ptr;
  378. } Descriptor;
  379. Descriptor.Size = 17;
  380. Descriptor.Ptr = tbuf;
  381. SYS$ASCTIM (0, &Descriptor, 0, 0);
  382. #endif /* not VMS */
  383. vms_debug2 ((6, "vmstimestring:'%s'\n", tbuf));
  384. return tbuf;
  385. }
  386. /* Create module name from filename (ie, extract the basename and convert it
  387. in upper cases). Works on both VMS and UNIX pathes.
  388. The result has to be free(). */
  389. char *
  390. vms_get_module_name (const char *filename, bool upcase)
  391. {
  392. char *fname, *fptr;
  393. const char *fout;
  394. /* Strip VMS path. */
  395. fout = strrchr (filename, ']');
  396. if (fout == NULL)
  397. fout = strchr (filename, ':');
  398. if (fout != NULL)
  399. fout++;
  400. else
  401. fout = filename;
  402. /* Strip UNIX path. */
  403. fptr = strrchr (fout, '/');
  404. if (fptr != NULL)
  405. fout = fptr + 1;
  406. fname = strdup (fout);
  407. /* Strip suffix. */
  408. fptr = strrchr (fname, '.');
  409. if (fptr != 0)
  410. *fptr = 0;
  411. /* Convert to upper case and truncate at 31 characters.
  412. (VMS object file format restricts module name length to 31). */
  413. fptr = fname;
  414. for (fptr = fname; *fptr != 0; fptr++)
  415. {
  416. if (*fptr == ';' || (fptr - fname) >= 31)
  417. {
  418. *fptr = 0;
  419. break;
  420. }
  421. if (upcase)
  422. *fptr = TOUPPER (*fptr);
  423. }
  424. return fname;
  425. }
  426. /* Compared to usual UNIX time_t, VMS time has less limits:
  427. - 64 bit (63 bits in fact as the MSB must be 0)
  428. - 100ns granularity
  429. - epoch is Nov 17, 1858.
  430. Here has the constants and the routines used to convert VMS from/to UNIX time.
  431. The conversion routines don't assume 64 bits arithmetic.
  432. Here we assume that the definition of time_t is the UNIX one, ie integer
  433. type, expressing seconds since the epoch. */
  434. /* UNIX time granularity for VMS, ie 1s / 100ns. */
  435. #define VMS_TIME_FACTOR 10000000
  436. /* Number of seconds since VMS epoch of the UNIX epoch. */
  437. #define VMS_TIME_OFFSET 3506716800U
  438. /* Convert a VMS time to a unix time. */
  439. time_t
  440. vms_time_to_time_t (unsigned int hi, unsigned int lo)
  441. {
  442. unsigned int tmp;
  443. unsigned int rlo;
  444. int i;
  445. time_t res;
  446. /* First convert to seconds. */
  447. tmp = hi % VMS_TIME_FACTOR;
  448. hi = hi / VMS_TIME_FACTOR;
  449. rlo = 0;
  450. for (i = 0; i < 4; i++)
  451. {
  452. tmp = (tmp << 8) | (lo >> 24);
  453. lo <<= 8;
  454. rlo = (rlo << 8) | (tmp / VMS_TIME_FACTOR);
  455. tmp %= VMS_TIME_FACTOR;
  456. }
  457. lo = rlo;
  458. /* Return 0 in case of overflow. */
  459. if (hi > 1
  460. || (hi == 1 && lo >= VMS_TIME_OFFSET))
  461. return 0;
  462. /* Return 0 in case of underflow. */
  463. if (hi == 0 && lo < VMS_TIME_OFFSET)
  464. return 0;
  465. res = lo - VMS_TIME_OFFSET;
  466. if (res <= 0)
  467. return 0;
  468. return res;
  469. }
  470. /* Convert a time_t to a VMS time. */
  471. void
  472. vms_time_t_to_vms_time (time_t ut, unsigned int *hi, unsigned int *lo)
  473. {
  474. unsigned int val[4];
  475. unsigned int tmp[4];
  476. unsigned int carry;
  477. int i;
  478. /* Put into val. */
  479. val[0] = ut & 0xffff;
  480. val[1] = (ut >> 16) & 0xffff;
  481. val[2] = sizeof (ut) > 4 ? (ut >> 32) & 0xffff : 0;
  482. val[3] = sizeof (ut) > 4 ? (ut >> 48) & 0xffff : 0;
  483. /* Add offset. */
  484. tmp[0] = VMS_TIME_OFFSET & 0xffff;
  485. tmp[1] = VMS_TIME_OFFSET >> 16;
  486. tmp[2] = 0;
  487. tmp[3] = 0;
  488. carry = 0;
  489. for (i = 0; i < 4; i++)
  490. {
  491. carry += tmp[i] + val[i];
  492. val[i] = carry & 0xffff;
  493. carry = carry >> 16;
  494. }
  495. /* Multiply by factor, well first by 10000 and then by 1000. */
  496. carry = 0;
  497. for (i = 0; i < 4; i++)
  498. {
  499. carry += val[i] * 10000;
  500. val[i] = carry & 0xffff;
  501. carry = carry >> 16;
  502. }
  503. carry = 0;
  504. for (i = 0; i < 4; i++)
  505. {
  506. carry += val[i] * 1000;
  507. val[i] = carry & 0xffff;
  508. carry = carry >> 16;
  509. }
  510. /* Write the result. */
  511. *lo = val[0] | (val[1] << 16);
  512. *hi = val[2] | (val[3] << 16);
  513. }
  514. /* Convert a raw (stored in a buffer) VMS time to a unix time. */
  515. time_t
  516. vms_rawtime_to_time_t (unsigned char *buf)
  517. {
  518. unsigned int hi = bfd_getl32 (buf + 4);
  519. unsigned int lo = bfd_getl32 (buf + 0);
  520. return vms_time_to_time_t (hi, lo);
  521. }
  522. void
  523. vms_get_time (unsigned int *hi, unsigned int *lo)
  524. {
  525. #ifdef VMS
  526. struct _generic_64 t;
  527. sys$gettim (&t);
  528. *lo = t.gen64$q_quadword;
  529. *hi = t.gen64$q_quadword >> 32;
  530. #else
  531. time_t t;
  532. time (&t);
  533. vms_time_t_to_vms_time (t, hi, lo);
  534. #endif
  535. }
  536. /* Get the current time into a raw buffer BUF. */
  537. void
  538. vms_raw_get_time (unsigned char *buf)
  539. {
  540. unsigned int hi, lo;
  541. vms_get_time (&hi, &lo);
  542. bfd_putl32 (lo, buf + 0);
  543. bfd_putl32 (hi, buf + 4);
  544. }