PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/byterun/debugger.c

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