acn1.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /*
  2. * Trace support for machine code stuff.
  3. * Only useful for 64-bit systems (at present)
  4. */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <inttypes.h>
  8. #include <string.h>
  9. #include <inttypes.h>
  10. #include <errno.h>
  11. #include <unistd.h>
  12. #if defined __linux__ || defined __CYGWIN__
  13. #define _(x) _ ## x
  14. #else
  15. #define _(x) x
  16. #endif
  17. //
  18. // The next few functions read values of various widths from
  19. // an address, or set read_ok to 0 and return 0. They are used in
  20. // debug printing so that if bad pointers arise the result can
  21. // still be some controlled output rather than an abort.
  22. //
  23. static int read_ok;
  24. #ifdef __WIN32__
  25. // At present (at least) I do not know a good way to see if a memory
  26. // address can be read without crashing on Winows. There are functions
  27. // such as IsBadReadPtr() which look encouraging, however further
  28. // investigation shows several severe issues with that route:
  29. // (1) It is not thread-safe, in that another thread could cause access
  30. // rights to a memory block to alter at any time. I am not that
  31. // worried about such problems at present!
  32. // (2) Windows uses guard pages to implement lazy stack expansion. A
  33. // use of IsBadReadPtr() that investigated an address that was in a
  34. // guard page could trigger the trap, but then not reset it, so that
  35. // subsequent need for stack expansion could result in a fatal error.
  36. // Arbitrary other parts of library code may also use guard pages that
  37. // might be put into non-standard states by use of IsBadReadPrt().
  38. // This is potentially severe, and really to be sensible the function
  39. // should not have side effects.
  40. #include <windows.h>
  41. static int safe_read_byte(void *p)
  42. { if (IsBadReadPtr(p, 1))
  43. { read_ok = 0;
  44. return 0;
  45. }
  46. read_ok = 1;
  47. return *(const char *)p;
  48. }
  49. static int safe_read_hw(void *p)
  50. { if (IsBadReadPtr(p, 2))
  51. { read_ok = 0;
  52. return 0;
  53. }
  54. read_ok = 1;
  55. return *(const int16_t *)p;
  56. }
  57. static int32_t safe_read_int32(void *p)
  58. { if (IsBadReadPtr(p, 4))
  59. { read_ok = 0;
  60. return 0;
  61. }
  62. read_ok = 1;
  63. return *(const int32_t *)p;
  64. }
  65. static int64_t safe_read_int64(void *p)
  66. { if (IsBadReadPtr(p, 8))
  67. { read_ok = 0;
  68. return 0;
  69. }
  70. read_ok = 1;
  71. return *(const int64_t *)p;
  72. }
  73. #else
  74. // For systems other than Windows I will exploit an expectation that
  75. // write() returns with a nice error code if the buffer it is given is not
  76. // accessible. I will write to /dev/random because doing so ought to be
  77. // pretty harmless.
  78. // I wonder if the use of write() here could have the adverse effects
  79. // on guard pages ort suchlike here as it could on Windows?
  80. #include <fcntl.h>
  81. static int randfd = -1;
  82. static void prepare_randfd()
  83. { if (randfd == -1)
  84. { randfd = open("/dev/random", O_RDWR);
  85. if (randfd == -1)
  86. { fprintf(stderr, "Unable to open /dev/rand\n");
  87. exit(1);
  88. }
  89. }
  90. read_ok = 0;
  91. }
  92. static int safe_read_byte(void *p)
  93. { prepare_randfd();
  94. if (write(randfd, p, 1) == -1 &&
  95. errno == EFAULT) return 0; /* Failure case */
  96. read_ok = 1;
  97. return *(const char *)p;
  98. }
  99. static int safe_read_hw(void *p)
  100. { prepare_randfd();
  101. if (write(randfd, p, 2) == -1 &&
  102. errno == EFAULT) return 0; /* Failure case */
  103. read_ok = 1;
  104. return *(const int16_t *)p;
  105. }
  106. static int32_t safe_read_int32(void *p)
  107. { prepare_randfd();
  108. if (write(randfd, p, 4) == -1 &&
  109. errno == EFAULT) return 0; /* Failure case */
  110. read_ok = 1;
  111. return *(const int32_t *)p;
  112. }
  113. static int64_t safe_read_int64(void *p)
  114. { prepare_randfd();
  115. if (write(randfd, p, 8) == -1 &&
  116. errno == EFAULT) return 0; /* Failure case */
  117. read_ok = 1;
  118. return *(const int64_t *)p;
  119. }
  120. #endif
  121. /*
  122. * In principle PSL could use different tag values on each architecture.
  123. * Well it will certainly do different things on 32 and 64-bit ones. But
  124. * It looks as if all 64-bit systems match what I am using here.
  125. */
  126. #define TAG_POSINT 0
  127. #define TAG_FIXNUM 1
  128. #define TAG_BIGNUM 2
  129. #define TAG_FLOATNUM 3
  130. #define TAG_STRING 4
  131. #define TAG_BYTES 5
  132. #define TAG_HALFWORDS 6
  133. #define TAG_WORDS 7
  134. #define TAG_VECTOR 8
  135. #define TAG_PAIR 9
  136. #define TAG_NEGINT 0xff
  137. #define TAG_ID 0xfe
  138. #define TAG_UNBOUND 0xfd
  139. extern int64_t _(symnam);
  140. #define SYMNAM(n) ((&_(symnam))[n])
  141. #define TAGOF(a) ((int)(((uint64_t)(a)) >> 56) & 0xff)
  142. #define INFOF(a) ((((uint64_t)(a)) << 8) >> 8)
  143. #define CAR(a) (((uint64_t *)INFOF(a))[0])
  144. #define CDR(a) (((uint64_t *)INFOF(a))[1])
  145. int iscons(uint64_t a)
  146. { return (TAGOF(a) == TAG_PAIR);
  147. }
  148. void lisp_print(uint64_t a)
  149. { int tag = TAGOF(a);
  150. uint64_t v = INFOF(a);
  151. int ch;
  152. switch (tag)
  153. {
  154. case TAG_POSINT: // posint
  155. fprintf(stderr, "%" PRId64, a);
  156. break;
  157. case TAG_STRING: // string
  158. safe_read_int64((void *)v);
  159. if (read_ok)
  160. { ch = 1 + (int)CAR(a);
  161. fprintf(stderr, "\"%.*s\"", ch, (char *)(v + 8));
  162. }
  163. else fprintf(stderr, "\"?BAD\"");
  164. break;
  165. case TAG_PAIR: // pair
  166. ch = '(';
  167. while (iscons(a))
  168. { safe_read_int64((void *)INFOF(a));
  169. if (!read_ok)
  170. { fprintf(stderr, "?BADCONS?");
  171. break;
  172. }
  173. putc(ch, stderr);
  174. ch = ' ';
  175. lisp_print(CAR(a));
  176. a = CDR(a);
  177. }
  178. safe_read_int64((void *)INFOF(a));
  179. if (!read_ok) break;
  180. fprintf(stderr, " . ");
  181. lisp_print(a);
  182. putc(')', stderr);
  183. break;
  184. case TAG_NEGINT: // negint
  185. fprintf(stderr, "%" PRId64, (int64_t)a);
  186. break;
  187. case TAG_ID: // id
  188. fprintf(stderr, "ID%" PRIx64, a); fflush(stdout);
  189. safe_read_int64(&SYMNAM(INFOF(a)));
  190. #if 1
  191. fprintf(stderr, "?some id?");
  192. #else
  193. if (!read_ok) fprintf(stderr, "BadSym");
  194. else lisp_print(SYMNAM(INFOF(a)));
  195. #endif
  196. break;
  197. default:
  198. fprintf(stderr, "??%" PRIx64, a);
  199. break;
  200. }
  201. }
  202. const void *acn1(const char *fmt, void *a, void *b, void *c)
  203. { void *v[4];
  204. v[0] = a;
  205. v[1] = b;
  206. v[2] = c;
  207. void **vp = v;
  208. int ch;
  209. void *arg;
  210. while ((ch = *fmt++) != 0)
  211. { if (ch != '%')
  212. { putc(ch, stderr);
  213. continue;
  214. }
  215. if ((ch = *fmt++) == 0) break;
  216. switch (ch)
  217. {
  218. case '%':
  219. putc(ch, stderr);
  220. break;
  221. default:
  222. arg = *vp++;
  223. fprintf(stderr, "%p :", arg);
  224. lisp_print((uint64_t)arg);
  225. break;
  226. }
  227. }
  228. fprintf(stderr, "\n");
  229. fflush(stderr);
  230. return fmt;
  231. }
  232. const void *_acn1(const char *fmt, void *a, void *b, void *c)
  233. { return acn1(fmt, a, b, c);
  234. }
  235. /* end of acn1.c */