PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/ocaml-4.00.0+beta2/byterun/debugger.c

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