PageRenderTime 49ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/byterun/debugger.c

http://github.com/bmeurer/ocaml
C | 439 lines | 374 code | 37 blank | 28 comment | 47 complexity | eb472c052ea32aab13ad43359b9d25e6 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0
  1. /***********************************************************************/
  2. /* */
  3. /* OCaml */
  4. /* */
  5. /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
  6. /* */
  7. /* Copyright 1996 Institut National de Recherche en Informatique et */
  8. /* en Automatique. All rights reserved. This file is distributed */
  9. /* under the terms of the GNU Library General Public License, with */
  10. /* the special exception on linking described in file ../LICENSE. */
  11. /* */
  12. /***********************************************************************/
  13. /* Interface with the byte-code debugger */
  14. #ifdef _WIN32
  15. #include <io.h>
  16. #endif /* _WIN32 */
  17. #include <string.h>
  18. #include "alloc.h"
  19. #include "config.h"
  20. #include "debugger.h"
  21. #include "misc.h"
  22. int caml_debugger_in_use = 0;
  23. uintnat caml_event_count;
  24. int caml_debugger_fork_mode = 1; /* parent by default */
  25. value marshal_flags = Val_emptylist;
  26. #if !defined(HAS_SOCKETS) || defined(NATIVE_CODE)
  27. void caml_debugger_init(void)
  28. {
  29. }
  30. void caml_debugger(enum event_kind event)
  31. {
  32. }
  33. void caml_debugger_cleanup_fork(void)
  34. {
  35. }
  36. #else
  37. #ifdef HAS_UNISTD
  38. #include <unistd.h>
  39. #endif
  40. #include <errno.h>
  41. #include <sys/types.h>
  42. #ifndef _WIN32
  43. #include <sys/wait.h>
  44. #include <sys/socket.h>
  45. #include <sys/un.h>
  46. #include <netinet/in.h>
  47. #include <arpa/inet.h>
  48. #include <netdb.h>
  49. #else
  50. #define ATOM ATOM_WS
  51. #include <winsock.h>
  52. #undef ATOM
  53. #include <process.h>
  54. #endif
  55. #include "fail.h"
  56. #include "fix_code.h"
  57. #include "instruct.h"
  58. #include "intext.h"
  59. #include "io.h"
  60. #include "mlvalues.h"
  61. #include "stacks.h"
  62. #include "sys.h"
  63. static int sock_domain; /* Socket domain for the debugger */
  64. static union { /* Socket address for the debugger */
  65. struct sockaddr s_gen;
  66. #ifndef _WIN32
  67. struct sockaddr_un s_unix;
  68. #endif
  69. struct sockaddr_in s_inet;
  70. } sock_addr;
  71. static int sock_addr_len; /* Length of sock_addr */
  72. static int dbg_socket = -1; /* The socket connected to the debugger */
  73. static struct channel * dbg_in; /* Input channel on the socket */
  74. static struct channel * dbg_out;/* Output channel on the socket */
  75. static char *dbg_addr = "(none)";
  76. static void open_connection(void)
  77. {
  78. #ifdef _WIN32
  79. /* Set socket to synchronous mode so that file descriptor-oriented
  80. functions (read()/write() etc.) can be used */
  81. int oldvalue, oldvaluelen, newvalue, retcode;
  82. oldvaluelen = sizeof(oldvalue);
  83. retcode = getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
  84. (char *) &oldvalue, &oldvaluelen);
  85. if (retcode == 0) {
  86. newvalue = SO_SYNCHRONOUS_NONALERT;
  87. setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
  88. (char *) &newvalue, sizeof(newvalue));
  89. }
  90. #endif
  91. dbg_socket = socket(sock_domain, SOCK_STREAM, 0);
  92. #ifdef _WIN32
  93. if (retcode == 0) {
  94. /* Restore initial mode */
  95. setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
  96. (char *) &oldvalue, oldvaluelen);
  97. }
  98. #endif
  99. if (dbg_socket == -1 ||
  100. connect(dbg_socket, &sock_addr.s_gen, sock_addr_len) == -1){
  101. caml_fatal_error_arg2 ("cannot connect to debugger at %s\n", dbg_addr,
  102. "error: %s\n", strerror (errno));
  103. }
  104. #ifdef _WIN32
  105. dbg_socket = _open_osfhandle(dbg_socket, 0);
  106. if (dbg_socket == -1)
  107. caml_fatal_error("_open_osfhandle failed");
  108. #endif
  109. dbg_in = caml_open_descriptor_in(dbg_socket);
  110. dbg_out = caml_open_descriptor_out(dbg_socket);
  111. if (!caml_debugger_in_use) caml_putword(dbg_out, -1); /* first connection */
  112. #ifdef _WIN32
  113. caml_putword(dbg_out, _getpid());
  114. #else
  115. caml_putword(dbg_out, getpid());
  116. #endif
  117. caml_flush(dbg_out);
  118. }
  119. static void close_connection(void)
  120. {
  121. caml_close_channel(dbg_in);
  122. caml_close_channel(dbg_out);
  123. dbg_socket = -1; /* was closed by caml_close_channel */
  124. }
  125. #ifdef _WIN32
  126. static void winsock_startup(void)
  127. {
  128. WSADATA wsaData;
  129. int err = WSAStartup(MAKEWORD(2, 0), &wsaData);
  130. if (err) caml_fatal_error("WSAStartup failed");
  131. }
  132. static void winsock_cleanup(void)
  133. {
  134. WSACleanup();
  135. }
  136. #endif
  137. void caml_debugger_init(void)
  138. {
  139. char * address;
  140. char * port, * p;
  141. struct hostent * host;
  142. int n;
  143. caml_register_global_root(&marshal_flags);
  144. marshal_flags = caml_alloc(2, Tag_cons);
  145. Store_field(marshal_flags, 0, Val_int(1)); /* Marshal.Closures */
  146. Store_field(marshal_flags, 1, Val_emptylist);
  147. address = getenv("CAML_DEBUG_SOCKET");
  148. if (address == NULL) return;
  149. dbg_addr = address;
  150. #ifdef _WIN32
  151. winsock_startup();
  152. (void)atexit(winsock_cleanup);
  153. #endif
  154. /* Parse the address */
  155. port = NULL;
  156. for (p = address; *p != 0; p++) {
  157. if (*p == ':') { *p = 0; port = p+1; break; }
  158. }
  159. if (port == NULL) {
  160. #ifndef _WIN32
  161. /* Unix domain */
  162. sock_domain = PF_UNIX;
  163. sock_addr.s_unix.sun_family = AF_UNIX;
  164. strncpy(sock_addr.s_unix.sun_path, address,
  165. sizeof(sock_addr.s_unix.sun_path));
  166. sock_addr_len =
  167. ((char *)&(sock_addr.s_unix.sun_path) - (char *)&(sock_addr.s_unix))
  168. + strlen(address);
  169. #else
  170. caml_fatal_error("Unix sockets not supported");
  171. #endif
  172. } else {
  173. /* Internet domain */
  174. sock_domain = PF_INET;
  175. for (p = (char *) &sock_addr.s_inet, n = sizeof(sock_addr.s_inet);
  176. n > 0; n--) *p++ = 0;
  177. sock_addr.s_inet.sin_family = AF_INET;
  178. sock_addr.s_inet.sin_addr.s_addr = inet_addr(address);
  179. if (sock_addr.s_inet.sin_addr.s_addr == -1) {
  180. host = gethostbyname(address);
  181. if (host == NULL)
  182. caml_fatal_error_arg("Unknown debugging host %s\n", address);
  183. memmove(&sock_addr.s_inet.sin_addr, host->h_addr, host->h_length);
  184. }
  185. sock_addr.s_inet.sin_port = htons(atoi(port));
  186. sock_addr_len = sizeof(sock_addr.s_inet);
  187. }
  188. open_connection();
  189. caml_debugger_in_use = 1;
  190. caml_trap_barrier = caml_stack_high;
  191. }
  192. static value getval(struct channel *chan)
  193. {
  194. value res;
  195. if (caml_really_getblock(chan, (char *) &res, sizeof(res)) == 0)
  196. caml_raise_end_of_file(); /* Bad, but consistent with caml_getword */
  197. return res;
  198. }
  199. static void putval(struct channel *chan, value val)
  200. {
  201. caml_really_putblock(chan, (char *) &val, sizeof(val));
  202. }
  203. static void safe_output_value(struct channel *chan, value val)
  204. {
  205. struct longjmp_buffer raise_buf, * saved_external_raise;
  206. /* Catch exceptions raised by [caml_output_val] */
  207. saved_external_raise = caml_external_raise;
  208. if (sigsetjmp(raise_buf.buf, 0) == 0) {
  209. caml_external_raise = &raise_buf;
  210. caml_output_val(chan, val, marshal_flags);
  211. } else {
  212. /* Send wrong magic number, will cause [caml_input_value] to fail */
  213. caml_really_putblock(chan, "\000\000\000\000", 4);
  214. }
  215. caml_external_raise = saved_external_raise;
  216. }
  217. #define Pc(sp) ((code_t)((sp)[0]))
  218. #define Env(sp) ((sp)[1])
  219. #define Extra_args(sp) (Long_val(((sp)[2])))
  220. #define Locals(sp) ((sp) + 3)
  221. void caml_debugger(enum event_kind event)
  222. {
  223. value * frame;
  224. intnat i, pos;
  225. value val;
  226. if (dbg_socket == -1) return; /* Not connected to a debugger. */
  227. /* Reset current frame */
  228. frame = caml_extern_sp + 1;
  229. /* Report the event to the debugger */
  230. switch(event) {
  231. case PROGRAM_START: /* Nothing to report */
  232. goto command_loop;
  233. case EVENT_COUNT:
  234. putch(dbg_out, REP_EVENT);
  235. break;
  236. case BREAKPOINT:
  237. putch(dbg_out, REP_BREAKPOINT);
  238. break;
  239. case PROGRAM_EXIT:
  240. putch(dbg_out, REP_EXITED);
  241. break;
  242. case TRAP_BARRIER:
  243. putch(dbg_out, REP_TRAP);
  244. break;
  245. case UNCAUGHT_EXC:
  246. putch(dbg_out, REP_UNCAUGHT_EXC);
  247. break;
  248. }
  249. caml_putword(dbg_out, caml_event_count);
  250. if (event == EVENT_COUNT || event == BREAKPOINT) {
  251. caml_putword(dbg_out, caml_stack_high - frame);
  252. caml_putword(dbg_out, (Pc(frame) - caml_start_code) * sizeof(opcode_t));
  253. } else {
  254. /* No PC and no stack frame associated with other events */
  255. caml_putword(dbg_out, 0);
  256. caml_putword(dbg_out, 0);
  257. }
  258. caml_flush(dbg_out);
  259. command_loop:
  260. /* Read and execute the commands sent by the debugger */
  261. while(1) {
  262. switch(getch(dbg_in)) {
  263. case REQ_SET_EVENT:
  264. pos = caml_getword(dbg_in);
  265. Assert (pos >= 0);
  266. Assert (pos < caml_code_size);
  267. caml_set_instruction(caml_start_code + pos / sizeof(opcode_t), EVENT);
  268. break;
  269. case REQ_SET_BREAKPOINT:
  270. pos = caml_getword(dbg_in);
  271. Assert (pos >= 0);
  272. Assert (pos < caml_code_size);
  273. caml_set_instruction(caml_start_code + pos / sizeof(opcode_t), BREAK);
  274. break;
  275. case REQ_RESET_INSTR:
  276. pos = caml_getword(dbg_in);
  277. Assert (pos >= 0);
  278. Assert (pos < caml_code_size);
  279. pos = pos / sizeof(opcode_t);
  280. caml_set_instruction(caml_start_code + pos, caml_saved_code[pos]);
  281. break;
  282. case REQ_CHECKPOINT:
  283. #ifndef _WIN32
  284. i = fork();
  285. if (i == 0) {
  286. close_connection(); /* Close parent connection. */
  287. open_connection(); /* Open new connection with debugger */
  288. } else {
  289. caml_putword(dbg_out, i);
  290. caml_flush(dbg_out);
  291. }
  292. #else
  293. caml_fatal_error("error: REQ_CHECKPOINT command");
  294. exit(-1);
  295. #endif
  296. break;
  297. case REQ_GO:
  298. caml_event_count = caml_getword(dbg_in);
  299. return;
  300. case REQ_STOP:
  301. exit(0);
  302. break;
  303. case REQ_WAIT:
  304. #ifndef _WIN32
  305. wait(NULL);
  306. #else
  307. caml_fatal_error("Fatal error: REQ_WAIT command");
  308. exit(-1);
  309. #endif
  310. break;
  311. case REQ_INITIAL_FRAME:
  312. frame = caml_extern_sp + 1;
  313. /* Fall through */
  314. case REQ_GET_FRAME:
  315. caml_putword(dbg_out, caml_stack_high - frame);
  316. if (frame < caml_stack_high){
  317. caml_putword(dbg_out, (Pc(frame) - caml_start_code) * sizeof(opcode_t));
  318. }else{
  319. caml_putword (dbg_out, 0);
  320. }
  321. caml_flush(dbg_out);
  322. break;
  323. case REQ_SET_FRAME:
  324. i = caml_getword(dbg_in);
  325. frame = caml_stack_high - i;
  326. break;
  327. case REQ_UP_FRAME:
  328. i = caml_getword(dbg_in);
  329. if (frame + Extra_args(frame) + i + 3 >= caml_stack_high) {
  330. caml_putword(dbg_out, -1);
  331. } else {
  332. frame += Extra_args(frame) + i + 3;
  333. caml_putword(dbg_out, caml_stack_high - frame);
  334. caml_putword(dbg_out, (Pc(frame) - caml_start_code) * sizeof(opcode_t));
  335. }
  336. caml_flush(dbg_out);
  337. break;
  338. case REQ_SET_TRAP_BARRIER:
  339. i = caml_getword(dbg_in);
  340. caml_trap_barrier = caml_stack_high - i;
  341. break;
  342. case REQ_GET_LOCAL:
  343. i = caml_getword(dbg_in);
  344. putval(dbg_out, Locals(frame)[i]);
  345. caml_flush(dbg_out);
  346. break;
  347. case REQ_GET_ENVIRONMENT:
  348. i = caml_getword(dbg_in);
  349. putval(dbg_out, Field(Env(frame), i));
  350. caml_flush(dbg_out);
  351. break;
  352. case REQ_GET_GLOBAL:
  353. i = caml_getword(dbg_in);
  354. putval(dbg_out, Field(caml_global_data, i));
  355. caml_flush(dbg_out);
  356. break;
  357. case REQ_GET_ACCU:
  358. putval(dbg_out, *caml_extern_sp);
  359. caml_flush(dbg_out);
  360. break;
  361. case REQ_GET_HEADER:
  362. val = getval(dbg_in);
  363. caml_putword(dbg_out, Hd_val(val));
  364. caml_flush(dbg_out);
  365. break;
  366. case REQ_GET_FIELD:
  367. val = getval(dbg_in);
  368. i = caml_getword(dbg_in);
  369. if (Tag_val(val) != Double_array_tag) {
  370. putch(dbg_out, 0);
  371. putval(dbg_out, Field(val, i));
  372. } else {
  373. double d = Double_field(val, i);
  374. putch(dbg_out, 1);
  375. caml_really_putblock(dbg_out, (char *) &d, 8);
  376. }
  377. caml_flush(dbg_out);
  378. break;
  379. case REQ_MARSHAL_OBJ:
  380. val = getval(dbg_in);
  381. safe_output_value(dbg_out, val);
  382. caml_flush(dbg_out);
  383. break;
  384. case REQ_GET_CLOSURE_CODE:
  385. val = getval(dbg_in);
  386. caml_putword(dbg_out, (Code_val(val)-caml_start_code) * sizeof(opcode_t));
  387. caml_flush(dbg_out);
  388. break;
  389. case REQ_SET_FORK_MODE:
  390. caml_debugger_fork_mode = caml_getword(dbg_in);
  391. break;
  392. }
  393. }
  394. }
  395. void caml_debugger_cleanup_fork(void)
  396. {
  397. /* We could remove all of the breakpoints, but closing the connection
  398. * means that they'll just be skipped anyway. */
  399. close_connection();
  400. caml_debugger_in_use = 0;
  401. }
  402. #endif