PageRenderTime 69ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 2ms

/mono/mini/debugger-agent.c

https://bitbucket.org/danipen/mono
C | 8901 lines | 6533 code | 1402 blank | 966 comment | 1422 complexity | 859c5c1a8bab0fc94f2776ea793ecb01 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * debugger-agent.c: Soft Debugger back-end module
  3. *
  4. * Author:
  5. * Zoltan Varga (vargaz@gmail.com)
  6. *
  7. * Copyright 2009-2010 Novell, Inc.
  8. * Copyright 2011 Xamarin Inc.
  9. */
  10. #include <config.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #ifdef HAVE_SYS_TYPES_H
  15. #include <sys/types.h>
  16. #endif
  17. #ifdef HAVE_SYS_SELECT_H
  18. #include <sys/select.h>
  19. #endif
  20. #ifdef HAVE_SYS_SOCKET_H
  21. #include <sys/socket.h>
  22. #endif
  23. #ifdef HAVE_NETINET_TCP_H
  24. #include <netinet/tcp.h>
  25. #endif
  26. #ifdef HAVE_NETINET_IN_H
  27. #include <netinet/in.h>
  28. #endif
  29. #ifdef HAVE_NETDB_H
  30. #include <netdb.h>
  31. #endif
  32. #ifdef HAVE_UNISTD_H
  33. #include <unistd.h>
  34. #endif
  35. #include <errno.h>
  36. #include <glib.h>
  37. #ifdef HAVE_PTHREAD_H
  38. #include <pthread.h>
  39. #endif
  40. #ifdef HAVE_UCONTEXT_H
  41. #include <ucontext.h>
  42. #endif
  43. #ifdef HOST_WIN32
  44. #ifdef _MSC_VER
  45. #include <winsock2.h>
  46. #endif
  47. #include <ws2tcpip.h>
  48. #ifdef __GNUC__
  49. /* cygwin's headers do not seem to define these */
  50. void WSAAPI freeaddrinfo (struct addrinfo*);
  51. int WSAAPI getaddrinfo (const char*,const char*,const struct addrinfo*,
  52. struct addrinfo**);
  53. int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD,
  54. char*,DWORD,int);
  55. #endif
  56. #endif
  57. #ifdef PLATFORM_ANDROID
  58. #include <linux/in.h>
  59. #include <linux/tcp.h>
  60. #include <sys/endian.h>
  61. #endif
  62. #include <mono/metadata/mono-debug.h>
  63. #include <mono/metadata/mono-debug-debugger.h>
  64. #include <mono/metadata/debug-mono-symfile.h>
  65. #include <mono/metadata/gc-internal.h>
  66. #include <mono/metadata/threads-types.h>
  67. #include <mono/metadata/socket-io.h>
  68. #include <mono/metadata/assembly.h>
  69. #include <mono/utils/mono-semaphore.h>
  70. #include <mono/utils/mono-error-internals.h>
  71. #include <mono/utils/mono-stack-unwinding.h>
  72. #include <mono/utils/mono-time.h>
  73. #include <mono/utils/mono-threads.h>
  74. #include "debugger-agent.h"
  75. #include "mini.h"
  76. /*
  77. On iOS we can't use System.Environment.Exit () as it will do the wrong
  78. shutdown sequence.
  79. */
  80. #if !defined (TARGET_IOS)
  81. #define TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
  82. #endif
  83. #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
  84. #define DISABLE_DEBUGGER_AGENT 1
  85. #endif
  86. #ifdef DISABLE_SOFT_DEBUG
  87. #define DISABLE_DEBUGGER_AGENT 1
  88. #endif
  89. #ifndef DISABLE_DEBUGGER_AGENT
  90. #include <mono/io-layer/mono-mutex.h>
  91. /* Definitions to make backporting to 2.6 easier */
  92. //#define MonoInternalThread MonoThread
  93. //#define mono_thread_internal_current mono_thread_current
  94. #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
  95. typedef struct {
  96. gboolean enabled;
  97. char *transport;
  98. char *address;
  99. int log_level;
  100. char *log_file;
  101. gboolean suspend;
  102. gboolean server;
  103. gboolean onuncaught;
  104. GSList *onthrow;
  105. int timeout;
  106. char *launch;
  107. gboolean embedding;
  108. gboolean defer;
  109. int keepalive;
  110. } AgentConfig;
  111. typedef struct
  112. {
  113. int id;
  114. guint32 il_offset, native_offset;
  115. MonoDomain *domain;
  116. MonoMethod *method;
  117. /*
  118. * If method is gshared, this is the actual instance, otherwise this is equal to
  119. * method.
  120. */
  121. MonoMethod *actual_method;
  122. /*
  123. * This is the method which is visible to debugger clients. Same as method,
  124. * except for native-to-managed wrappers.
  125. */
  126. MonoMethod *api_method;
  127. MonoContext ctx;
  128. MonoDebugMethodJitInfo *jit;
  129. MonoJitInfo *ji;
  130. int flags;
  131. mgreg_t *reg_locations [MONO_MAX_IREGS];
  132. /*
  133. * Whenever ctx is set. This is FALSE for the last frame of running threads, since
  134. * the frame can become invalid.
  135. */
  136. gboolean has_ctx;
  137. } StackFrame;
  138. typedef struct _InvokeData InvokeData;
  139. struct _InvokeData
  140. {
  141. int id;
  142. int flags;
  143. guint8 *p;
  144. guint8 *endp;
  145. /* This is the context which needs to be restored after the invoke */
  146. MonoContext ctx;
  147. gboolean has_ctx;
  148. /*
  149. * If this is set, invoke this method with the arguments given by ARGS.
  150. */
  151. MonoMethod *method;
  152. gpointer *args;
  153. guint32 suspend_count;
  154. int nmethods;
  155. InvokeData *last_invoke;
  156. };
  157. typedef struct {
  158. MonoThreadUnwindState context;
  159. /* This is computed on demand when it is requested using the wire protocol */
  160. /* It is freed up when the thread is resumed */
  161. int frame_count;
  162. StackFrame **frames;
  163. /*
  164. * Whenever the frame info is up-to-date. If not, compute_frame_info () will need to
  165. * re-compute it.
  166. */
  167. gboolean frames_up_to_date;
  168. /*
  169. * Points to data about a pending invoke which needs to be executed after the thread
  170. * resumes.
  171. */
  172. InvokeData *pending_invoke;
  173. /*
  174. * Set to TRUE if this thread is suspended in suspend_current () or it is executing
  175. * native code.
  176. */
  177. gboolean suspended;
  178. /*
  179. * Signals whenever the thread is in the process of suspending, i.e. it will suspend
  180. * within a finite amount of time.
  181. */
  182. gboolean suspending;
  183. /*
  184. * Set to TRUE if this thread is suspended in suspend_current ().
  185. */
  186. gboolean really_suspended;
  187. /* Used to pass the context to the breakpoint/single step handler */
  188. MonoContext handler_ctx;
  189. /* Whenever thread_stop () was called for this thread */
  190. gboolean terminated;
  191. /* Number of thread interruptions not yet processed */
  192. gint32 interrupt_count;
  193. /* Whenever to disable breakpoints (used during invokes) */
  194. gboolean disable_breakpoints;
  195. /*
  196. * Number of times this thread has been resumed using resume_thread ().
  197. */
  198. guint32 resume_count;
  199. MonoInternalThread *thread;
  200. /*
  201. * Information about the frame which transitioned to native code for running
  202. * threads.
  203. */
  204. StackFrameInfo async_last_frame;
  205. /*
  206. * The context where the stack walk can be started for running threads.
  207. */
  208. MonoThreadUnwindState async_state;
  209. /*
  210. * The context used for filter clauses
  211. */
  212. MonoThreadUnwindState filter_state;
  213. /*
  214. * The callee address of the last mono_runtime_invoke call
  215. */
  216. gpointer invoke_addr;
  217. gboolean abort_requested;
  218. /*
  219. * The current mono_runtime_invoke invocation.
  220. */
  221. InvokeData *invoke;
  222. /*
  223. * The context where single stepping should resume while the thread is suspended because
  224. * of an EXCEPTION event.
  225. */
  226. MonoThreadUnwindState catch_state;
  227. /*
  228. * The context which needs to be restored after handling a single step/breakpoint
  229. * event. This is the same as the ctx at step/breakpoint site, but includes changes
  230. * to caller saved registers done by set_var ().
  231. */
  232. MonoContext restore_ctx;
  233. } DebuggerTlsData;
  234. typedef struct {
  235. const char *name;
  236. void (*connect) (const char *address);
  237. void (*close1) (void);
  238. void (*close2) (void);
  239. gboolean (*send) (void *buf, int len);
  240. int (*recv) (void *buf, int len);
  241. } DebuggerTransport;
  242. /*
  243. * Wire Protocol definitions
  244. */
  245. #define HEADER_LENGTH 11
  246. #define MAJOR_VERSION 2
  247. #define MINOR_VERSION 23
  248. typedef enum {
  249. CMD_SET_VM = 1,
  250. CMD_SET_OBJECT_REF = 9,
  251. CMD_SET_STRING_REF = 10,
  252. CMD_SET_THREAD = 11,
  253. CMD_SET_ARRAY_REF = 13,
  254. CMD_SET_EVENT_REQUEST = 15,
  255. CMD_SET_STACK_FRAME = 16,
  256. CMD_SET_APPDOMAIN = 20,
  257. CMD_SET_ASSEMBLY = 21,
  258. CMD_SET_METHOD = 22,
  259. CMD_SET_TYPE = 23,
  260. CMD_SET_MODULE = 24,
  261. CMD_SET_EVENT = 64
  262. } CommandSet;
  263. typedef enum {
  264. EVENT_KIND_VM_START = 0,
  265. EVENT_KIND_VM_DEATH = 1,
  266. EVENT_KIND_THREAD_START = 2,
  267. EVENT_KIND_THREAD_DEATH = 3,
  268. EVENT_KIND_APPDOMAIN_CREATE = 4,
  269. EVENT_KIND_APPDOMAIN_UNLOAD = 5,
  270. EVENT_KIND_METHOD_ENTRY = 6,
  271. EVENT_KIND_METHOD_EXIT = 7,
  272. EVENT_KIND_ASSEMBLY_LOAD = 8,
  273. EVENT_KIND_ASSEMBLY_UNLOAD = 9,
  274. EVENT_KIND_BREAKPOINT = 10,
  275. EVENT_KIND_STEP = 11,
  276. EVENT_KIND_TYPE_LOAD = 12,
  277. EVENT_KIND_EXCEPTION = 13,
  278. EVENT_KIND_KEEPALIVE = 14,
  279. EVENT_KIND_USER_BREAK = 15,
  280. EVENT_KIND_USER_LOG = 16
  281. } EventKind;
  282. typedef enum {
  283. SUSPEND_POLICY_NONE = 0,
  284. SUSPEND_POLICY_EVENT_THREAD = 1,
  285. SUSPEND_POLICY_ALL = 2
  286. } SuspendPolicy;
  287. typedef enum {
  288. ERR_NONE = 0,
  289. ERR_INVALID_OBJECT = 20,
  290. ERR_INVALID_FIELDID = 25,
  291. ERR_INVALID_FRAMEID = 30,
  292. ERR_NOT_IMPLEMENTED = 100,
  293. ERR_NOT_SUSPENDED = 101,
  294. ERR_INVALID_ARGUMENT = 102,
  295. ERR_UNLOADED = 103,
  296. ERR_NO_INVOCATION = 104,
  297. ERR_ABSENT_INFORMATION = 105,
  298. ERR_NO_SEQ_POINT_AT_IL_OFFSET = 106,
  299. ERR_LOADER_ERROR = 200, /*XXX extend the protocol to pass this information down the pipe */
  300. } ErrorCode;
  301. typedef enum {
  302. MOD_KIND_COUNT = 1,
  303. MOD_KIND_THREAD_ONLY = 3,
  304. MOD_KIND_LOCATION_ONLY = 7,
  305. MOD_KIND_EXCEPTION_ONLY = 8,
  306. MOD_KIND_STEP = 10,
  307. MOD_KIND_ASSEMBLY_ONLY = 11,
  308. MOD_KIND_SOURCE_FILE_ONLY = 12,
  309. MOD_KIND_TYPE_NAME_ONLY = 13
  310. } ModifierKind;
  311. typedef enum {
  312. STEP_DEPTH_INTO = 0,
  313. STEP_DEPTH_OVER = 1,
  314. STEP_DEPTH_OUT = 2
  315. } StepDepth;
  316. typedef enum {
  317. STEP_SIZE_MIN = 0,
  318. STEP_SIZE_LINE = 1
  319. } StepSize;
  320. typedef enum {
  321. STEP_FILTER_NONE = 0,
  322. STEP_FILTER_STATIC_CTOR = 1,
  323. STEP_FILTER_DEBUGGER_HIDDEN = 2
  324. } StepFilter;
  325. typedef enum {
  326. TOKEN_TYPE_STRING = 0,
  327. TOKEN_TYPE_TYPE = 1,
  328. TOKEN_TYPE_FIELD = 2,
  329. TOKEN_TYPE_METHOD = 3,
  330. TOKEN_TYPE_UNKNOWN = 4
  331. } DebuggerTokenType;
  332. typedef enum {
  333. VALUE_TYPE_ID_NULL = 0xf0,
  334. VALUE_TYPE_ID_TYPE = 0xf1
  335. } ValueTypeId;
  336. typedef enum {
  337. FRAME_FLAG_DEBUGGER_INVOKE = 1,
  338. FRAME_FLAG_NATIVE_TRANSITION = 2
  339. } StackFrameFlags;
  340. typedef enum {
  341. INVOKE_FLAG_DISABLE_BREAKPOINTS = 1,
  342. INVOKE_FLAG_SINGLE_THREADED = 2
  343. } InvokeFlags;
  344. typedef enum {
  345. BINDING_FLAGS_IGNORE_CASE = 0x70000000,
  346. } BindingFlagsExtensions;
  347. typedef enum {
  348. CMD_VM_VERSION = 1,
  349. CMD_VM_ALL_THREADS = 2,
  350. CMD_VM_SUSPEND = 3,
  351. CMD_VM_RESUME = 4,
  352. CMD_VM_EXIT = 5,
  353. CMD_VM_DISPOSE = 6,
  354. CMD_VM_INVOKE_METHOD = 7,
  355. CMD_VM_SET_PROTOCOL_VERSION = 8,
  356. CMD_VM_ABORT_INVOKE = 9,
  357. CMD_VM_SET_KEEPALIVE = 10,
  358. CMD_VM_GET_TYPES_FOR_SOURCE_FILE = 11,
  359. CMD_VM_GET_TYPES = 12,
  360. CMD_VM_INVOKE_METHODS = 13
  361. } CmdVM;
  362. typedef enum {
  363. CMD_THREAD_GET_FRAME_INFO = 1,
  364. CMD_THREAD_GET_NAME = 2,
  365. CMD_THREAD_GET_STATE = 3,
  366. CMD_THREAD_GET_INFO = 4,
  367. CMD_THREAD_GET_ID = 5,
  368. CMD_THREAD_GET_TID = 6
  369. } CmdThread;
  370. typedef enum {
  371. CMD_EVENT_REQUEST_SET = 1,
  372. CMD_EVENT_REQUEST_CLEAR = 2,
  373. CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS = 3
  374. } CmdEvent;
  375. typedef enum {
  376. CMD_COMPOSITE = 100
  377. } CmdComposite;
  378. typedef enum {
  379. CMD_APPDOMAIN_GET_ROOT_DOMAIN = 1,
  380. CMD_APPDOMAIN_GET_FRIENDLY_NAME = 2,
  381. CMD_APPDOMAIN_GET_ASSEMBLIES = 3,
  382. CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY = 4,
  383. CMD_APPDOMAIN_CREATE_STRING = 5,
  384. CMD_APPDOMAIN_GET_CORLIB = 6,
  385. CMD_APPDOMAIN_CREATE_BOXED_VALUE = 7
  386. } CmdAppDomain;
  387. typedef enum {
  388. CMD_ASSEMBLY_GET_LOCATION = 1,
  389. CMD_ASSEMBLY_GET_ENTRY_POINT = 2,
  390. CMD_ASSEMBLY_GET_MANIFEST_MODULE = 3,
  391. CMD_ASSEMBLY_GET_OBJECT = 4,
  392. CMD_ASSEMBLY_GET_TYPE = 5,
  393. CMD_ASSEMBLY_GET_NAME = 6
  394. } CmdAssembly;
  395. typedef enum {
  396. CMD_MODULE_GET_INFO = 1,
  397. } CmdModule;
  398. typedef enum {
  399. CMD_METHOD_GET_NAME = 1,
  400. CMD_METHOD_GET_DECLARING_TYPE = 2,
  401. CMD_METHOD_GET_DEBUG_INFO = 3,
  402. CMD_METHOD_GET_PARAM_INFO = 4,
  403. CMD_METHOD_GET_LOCALS_INFO = 5,
  404. CMD_METHOD_GET_INFO = 6,
  405. CMD_METHOD_GET_BODY = 7,
  406. CMD_METHOD_RESOLVE_TOKEN = 8,
  407. CMD_METHOD_GET_CATTRS = 9,
  408. } CmdMethod;
  409. typedef enum {
  410. CMD_TYPE_GET_INFO = 1,
  411. CMD_TYPE_GET_METHODS = 2,
  412. CMD_TYPE_GET_FIELDS = 3,
  413. CMD_TYPE_GET_VALUES = 4,
  414. CMD_TYPE_GET_OBJECT = 5,
  415. CMD_TYPE_GET_SOURCE_FILES = 6,
  416. CMD_TYPE_SET_VALUES = 7,
  417. CMD_TYPE_IS_ASSIGNABLE_FROM = 8,
  418. CMD_TYPE_GET_PROPERTIES = 9,
  419. CMD_TYPE_GET_CATTRS = 10,
  420. CMD_TYPE_GET_FIELD_CATTRS = 11,
  421. CMD_TYPE_GET_PROPERTY_CATTRS = 12,
  422. CMD_TYPE_GET_SOURCE_FILES_2 = 13,
  423. CMD_TYPE_GET_VALUES_2 = 14,
  424. CMD_TYPE_GET_METHODS_BY_NAME_FLAGS = 15,
  425. CMD_TYPE_GET_INTERFACES = 16,
  426. CMD_TYPE_GET_INTERFACE_MAP = 17,
  427. CMD_TYPE_IS_INITIALIZED = 18
  428. } CmdType;
  429. typedef enum {
  430. CMD_STACK_FRAME_GET_VALUES = 1,
  431. CMD_STACK_FRAME_GET_THIS = 2,
  432. CMD_STACK_FRAME_SET_VALUES = 3
  433. } CmdStackFrame;
  434. typedef enum {
  435. CMD_ARRAY_REF_GET_LENGTH = 1,
  436. CMD_ARRAY_REF_GET_VALUES = 2,
  437. CMD_ARRAY_REF_SET_VALUES = 3,
  438. } CmdArray;
  439. typedef enum {
  440. CMD_STRING_REF_GET_VALUE = 1,
  441. CMD_STRING_REF_GET_LENGTH = 2,
  442. CMD_STRING_REF_GET_CHARS = 3
  443. } CmdString;
  444. typedef enum {
  445. CMD_OBJECT_REF_GET_TYPE = 1,
  446. CMD_OBJECT_REF_GET_VALUES = 2,
  447. CMD_OBJECT_REF_IS_COLLECTED = 3,
  448. CMD_OBJECT_REF_GET_ADDRESS = 4,
  449. CMD_OBJECT_REF_GET_DOMAIN = 5,
  450. CMD_OBJECT_REF_SET_VALUES = 6,
  451. CMD_OBJECT_REF_GET_INFO = 7,
  452. } CmdObject;
  453. typedef struct {
  454. ModifierKind kind;
  455. union {
  456. int count; /* For kind == MOD_KIND_COUNT */
  457. MonoInternalThread *thread; /* For kind == MOD_KIND_THREAD_ONLY */
  458. MonoClass *exc_class; /* For kind == MONO_KIND_EXCEPTION_ONLY */
  459. MonoAssembly **assemblies; /* For kind == MONO_KIND_ASSEMBLY_ONLY */
  460. GHashTable *source_files; /* For kind == MONO_KIND_SOURCE_FILE_ONLY */
  461. GHashTable *type_names; /* For kind == MONO_KIND_TYPE_NAME_ONLY */
  462. StepFilter filter; /* For kind == MOD_KIND_STEP */
  463. } data;
  464. gboolean caught, uncaught; /* For kind == MOD_KIND_EXCEPTION_ONLY */
  465. } Modifier;
  466. typedef struct{
  467. int id;
  468. int event_kind;
  469. int suspend_policy;
  470. int nmodifiers;
  471. gpointer info;
  472. Modifier modifiers [MONO_ZERO_LEN_ARRAY];
  473. } EventRequest;
  474. /*
  475. * Describes a single step request.
  476. */
  477. typedef struct {
  478. EventRequest *req;
  479. MonoInternalThread *thread;
  480. StepDepth depth;
  481. StepSize size;
  482. StepFilter filter;
  483. gpointer last_sp;
  484. gpointer start_sp;
  485. MonoMethod *last_method;
  486. int last_line;
  487. /* Whenever single stepping is performed using start/stop_single_stepping () */
  488. gboolean global;
  489. /* The list of breakpoints used to implement step-over */
  490. GSList *bps;
  491. } SingleStepReq;
  492. /*
  493. * Contains additional information for an event
  494. */
  495. typedef struct {
  496. /* For EVENT_KIND_EXCEPTION */
  497. MonoObject *exc;
  498. MonoContext catch_ctx;
  499. gboolean caught;
  500. /* For EVENT_KIND_USER_LOG */
  501. int level;
  502. char *category, *message;
  503. /* For EVENT_KIND_TYPE_LOAD */
  504. MonoClass *klass;
  505. } EventInfo;
  506. /* Dummy structure used for the profiler callbacks */
  507. typedef struct {
  508. void* dummy;
  509. } DebuggerProfiler;
  510. #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
  511. #ifdef HOST_WIN32
  512. #define get_last_sock_error() WSAGetLastError()
  513. #define MONO_EWOULDBLOCK WSAEWOULDBLOCK
  514. #define MONO_EINTR WSAEINTR
  515. #else
  516. #define get_last_sock_error() errno
  517. #define MONO_EWOULDBLOCK EWOULDBLOCK
  518. #define MONO_EINTR EINTR
  519. #endif
  520. #define CHECK_PROTOCOL_VERSION(major,minor) \
  521. (protocol_version_set && (major_version > (major) || (major_version == (major) && minor_version >= (minor))))
  522. /*
  523. * Globals
  524. */
  525. static AgentConfig agent_config;
  526. /*
  527. * Whenever the agent is fully initialized.
  528. * When using the onuncaught or onthrow options, only some parts of the agent are
  529. * initialized on startup, and the full initialization which includes connection
  530. * establishment and the startup of the agent thread is only done in response to
  531. * an event.
  532. */
  533. static gint32 inited;
  534. #ifndef DISABLE_SOCKET_TRANSPORT
  535. static int conn_fd;
  536. static int listen_fd;
  537. #endif
  538. static int packet_id = 0;
  539. static int objref_id = 0;
  540. static int event_request_id = 0;
  541. static int frame_id = 0;
  542. static GPtrArray *event_requests;
  543. static MonoNativeTlsKey debugger_tls_id;
  544. static gboolean vm_start_event_sent, vm_death_event_sent, disconnected;
  545. /* Maps MonoInternalThread -> DebuggerTlsData */
  546. static MonoGHashTable *thread_to_tls;
  547. /* Maps tid -> MonoInternalThread */
  548. static MonoGHashTable *tid_to_thread;
  549. /* Maps tid -> MonoThread (not MonoInternalThread) */
  550. static MonoGHashTable *tid_to_thread_obj;
  551. static gsize debugger_thread_id;
  552. static HANDLE debugger_thread_handle;
  553. static int log_level;
  554. static gboolean embedding;
  555. static FILE *log_file;
  556. /* Assemblies whose assembly load event has no been sent yet */
  557. static GPtrArray *pending_assembly_loads;
  558. /* Whenever the debugger thread has exited */
  559. static gboolean debugger_thread_exited;
  560. /* Cond variable used to wait for debugger_thread_exited becoming true */
  561. static mono_cond_t debugger_thread_exited_cond;
  562. /* Mutex for the cond var above */
  563. static mono_mutex_t debugger_thread_exited_mutex;
  564. static DebuggerProfiler debugger_profiler;
  565. /* The single step request instance */
  566. static SingleStepReq *ss_req = NULL;
  567. static gpointer ss_invoke_addr = NULL;
  568. #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
  569. /* Number of single stepping operations in progress */
  570. static int ss_count;
  571. #endif
  572. /* The protocol version of the client */
  573. static int major_version, minor_version;
  574. /* Whenever the variables above are set by the client */
  575. static gboolean protocol_version_set;
  576. /* A hash table containing all active domains */
  577. static GHashTable *domains;
  578. /* The number of times the runtime is suspended */
  579. static gint32 suspend_count;
  580. static void transport_init (void);
  581. static void transport_connect (const char *address);
  582. static gboolean transport_handshake (void);
  583. static void register_transport (DebuggerTransport *trans);
  584. static guint32 WINAPI debugger_thread (void *arg);
  585. static void runtime_initialized (MonoProfiler *prof);
  586. static void runtime_shutdown (MonoProfiler *prof);
  587. static void thread_startup (MonoProfiler *prof, uintptr_t tid);
  588. static void thread_end (MonoProfiler *prof, uintptr_t tid);
  589. static void appdomain_load (MonoProfiler *prof, MonoDomain *domain, int result);
  590. static void appdomain_unload (MonoProfiler *prof, MonoDomain *domain);
  591. static void emit_appdomain_load (gpointer key, gpointer value, gpointer user_data);
  592. static void emit_thread_start (gpointer key, gpointer value, gpointer user_data);
  593. static void invalidate_each_thread (gpointer key, gpointer value, gpointer user_data);
  594. static void assembly_load (MonoProfiler *prof, MonoAssembly *assembly, int result);
  595. static void assembly_unload (MonoProfiler *prof, MonoAssembly *assembly);
  596. static void emit_assembly_load (gpointer assembly, gpointer user_data);
  597. static void emit_type_load (gpointer key, gpointer type, gpointer user_data);
  598. static void start_runtime_invoke (MonoProfiler *prof, MonoMethod *method);
  599. static void end_runtime_invoke (MonoProfiler *prof, MonoMethod *method);
  600. static void jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result);
  601. static void add_pending_breakpoints (MonoMethod *method, MonoJitInfo *jinfo);
  602. static void start_single_stepping (void);
  603. static void stop_single_stepping (void);
  604. static void suspend_current (void);
  605. static void clear_event_requests_for_assembly (MonoAssembly *assembly);
  606. static void clear_types_for_assembly (MonoAssembly *assembly);
  607. static void clear_breakpoints_for_domain (MonoDomain *domain);
  608. static void process_profiler_event (EventKind event, gpointer arg);
  609. /* Submodule init/cleanup */
  610. static void breakpoints_init (void);
  611. static void breakpoints_cleanup (void);
  612. static void objrefs_init (void);
  613. static void objrefs_cleanup (void);
  614. static void ids_init (void);
  615. static void ids_cleanup (void);
  616. static void suspend_init (void);
  617. static void ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch);
  618. static ErrorCode ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req);
  619. static void ss_destroy (SingleStepReq *req);
  620. static void start_debugger_thread (void);
  621. static void stop_debugger_thread (void);
  622. static void finish_agent_init (gboolean on_startup);
  623. static void process_profiler_event (EventKind event, gpointer arg);
  624. static void invalidate_frames (DebuggerTlsData *tls);
  625. #ifndef DISABLE_SOCKET_TRANSPORT
  626. static void
  627. register_socket_transport (void);
  628. #endif
  629. static int
  630. parse_address (char *address, char **host, int *port)
  631. {
  632. char *pos = strchr (address, ':');
  633. if (pos == NULL || pos == address)
  634. return 1;
  635. *host = g_malloc (pos - address + 1);
  636. strncpy (*host, address, pos - address);
  637. (*host) [pos - address] = '\0';
  638. *port = atoi (pos + 1);
  639. return 0;
  640. }
  641. static void
  642. print_usage (void)
  643. {
  644. fprintf (stderr, "Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
  645. fprintf (stderr, "Available options:\n");
  646. fprintf (stderr, " transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
  647. fprintf (stderr, " address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
  648. fprintf (stderr, " loglevel=<n>\t\t\tLog level (defaults to 0)\n");
  649. fprintf (stderr, " logfile=<file>\t\tFile to log to (defaults to stdout)\n");
  650. fprintf (stderr, " suspend=y/n\t\t\tWhether to suspend after startup.\n");
  651. fprintf (stderr, " timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
  652. fprintf (stderr, " server=y/n\t\t\tWhether to listen for a client connection.\n");
  653. fprintf (stderr, " keepalive=<n>\t\t\tSend keepalive events every n milliseconds.\n");
  654. fprintf (stderr, " help\t\t\t\tPrint this help.\n");
  655. }
  656. static gboolean
  657. parse_flag (const char *option, char *flag)
  658. {
  659. if (!strcmp (flag, "y"))
  660. return TRUE;
  661. else if (!strcmp (flag, "n"))
  662. return FALSE;
  663. else {
  664. fprintf (stderr, "debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option);
  665. exit (1);
  666. return FALSE;
  667. }
  668. }
  669. void
  670. mono_debugger_agent_parse_options (char *options)
  671. {
  672. char **args, **ptr;
  673. char *host;
  674. int port;
  675. char *extra;
  676. #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
  677. fprintf (stderr, "--debugger-agent is not supported on this platform.\n");
  678. exit (1);
  679. #endif
  680. extra = getenv ("MONO_SDB_ENV_OPTIONS");
  681. if (extra)
  682. options = g_strdup_printf ("%s,%s", options, extra);
  683. agent_config.enabled = TRUE;
  684. agent_config.suspend = TRUE;
  685. agent_config.server = FALSE;
  686. agent_config.defer = FALSE;
  687. agent_config.address = NULL;
  688. args = g_strsplit (options, ",", -1);
  689. for (ptr = args; ptr && *ptr; ptr ++) {
  690. char *arg = *ptr;
  691. if (strncmp (arg, "transport=", 10) == 0) {
  692. agent_config.transport = g_strdup (arg + 10);
  693. } else if (strncmp (arg, "address=", 8) == 0) {
  694. agent_config.address = g_strdup (arg + 8);
  695. } else if (strncmp (arg, "loglevel=", 9) == 0) {
  696. agent_config.log_level = atoi (arg + 9);
  697. } else if (strncmp (arg, "logfile=", 8) == 0) {
  698. agent_config.log_file = g_strdup (arg + 8);
  699. } else if (strncmp (arg, "suspend=", 8) == 0) {
  700. agent_config.suspend = parse_flag ("suspend", arg + 8);
  701. } else if (strncmp (arg, "server=", 7) == 0) {
  702. agent_config.server = parse_flag ("server", arg + 7);
  703. } else if (strncmp (arg, "onuncaught=", 11) == 0) {
  704. agent_config.onuncaught = parse_flag ("onuncaught", arg + 11);
  705. } else if (strncmp (arg, "onthrow=", 8) == 0) {
  706. /* We support multiple onthrow= options */
  707. agent_config.onthrow = g_slist_append (agent_config.onthrow, g_strdup (arg + 8));
  708. } else if (strncmp (arg, "onthrow", 7) == 0) {
  709. agent_config.onthrow = g_slist_append (agent_config.onthrow, g_strdup (""));
  710. } else if (strncmp (arg, "help", 4) == 0) {
  711. print_usage ();
  712. exit (0);
  713. } else if (strncmp (arg, "timeout=", 8) == 0) {
  714. agent_config.timeout = atoi (arg + 8);
  715. } else if (strncmp (arg, "launch=", 7) == 0) {
  716. agent_config.launch = g_strdup (arg + 7);
  717. } else if (strncmp (arg, "embedding=", 10) == 0) {
  718. agent_config.embedding = atoi (arg + 10) == 1;
  719. } else if (strncmp (arg, "keepalive=", 10) == 0) {
  720. agent_config.keepalive = atoi (arg + 10);
  721. } else {
  722. print_usage ();
  723. exit (1);
  724. }
  725. }
  726. if (agent_config.server && !agent_config.suspend) {
  727. /* Waiting for deferred attachment */
  728. agent_config.defer = TRUE;
  729. if (agent_config.address == NULL) {
  730. agent_config.address = g_strdup_printf ("0.0.0.0:%u", 56000 + (GetCurrentProcessId () % 1000));
  731. }
  732. }
  733. //agent_config.log_level = 0;
  734. if (agent_config.transport == NULL) {
  735. fprintf (stderr, "debugger-agent: The 'transport' option is mandatory.\n");
  736. exit (1);
  737. }
  738. if (agent_config.address == NULL && !agent_config.server) {
  739. fprintf (stderr, "debugger-agent: The 'address' option is mandatory.\n");
  740. exit (1);
  741. }
  742. // FIXME:
  743. if (!strcmp (agent_config.transport, "dt_socket")) {
  744. if (agent_config.address && parse_address (agent_config.address, &host, &port)) {
  745. fprintf (stderr, "debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
  746. exit (1);
  747. }
  748. }
  749. }
  750. void
  751. mono_debugger_agent_init (void)
  752. {
  753. if (!agent_config.enabled)
  754. return;
  755. transport_init ();
  756. /* Need to know whenever a thread has acquired the loader mutex */
  757. mono_loader_lock_track_ownership (TRUE);
  758. event_requests = g_ptr_array_new ();
  759. mono_mutex_init (&debugger_thread_exited_mutex, NULL);
  760. mono_cond_init (&debugger_thread_exited_cond, NULL);
  761. mono_profiler_install ((MonoProfiler*)&debugger_profiler, runtime_shutdown);
  762. mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS | MONO_PROFILE_THREADS | MONO_PROFILE_ASSEMBLY_EVENTS | MONO_PROFILE_JIT_COMPILATION | MONO_PROFILE_METHOD_EVENTS);
  763. mono_profiler_install_runtime_initialized (runtime_initialized);
  764. mono_profiler_install_appdomain (NULL, appdomain_load, NULL, appdomain_unload);
  765. mono_profiler_install_thread (thread_startup, thread_end);
  766. mono_profiler_install_assembly (NULL, assembly_load, assembly_unload, NULL);
  767. mono_profiler_install_jit_end (jit_end);
  768. mono_profiler_install_method_invoke (start_runtime_invoke, end_runtime_invoke);
  769. mono_native_tls_alloc (&debugger_tls_id, NULL);
  770. thread_to_tls = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC);
  771. MONO_GC_REGISTER_ROOT_FIXED (thread_to_tls);
  772. tid_to_thread = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
  773. MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread);
  774. tid_to_thread_obj = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
  775. MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread_obj);
  776. pending_assembly_loads = g_ptr_array_new ();
  777. domains = g_hash_table_new (mono_aligned_addr_hash, NULL);
  778. log_level = agent_config.log_level;
  779. embedding = agent_config.embedding;
  780. disconnected = TRUE;
  781. if (agent_config.log_file) {
  782. log_file = fopen (agent_config.log_file, "w+");
  783. if (!log_file) {
  784. fprintf (stderr, "Unable to create log file '%s': %s.\n", agent_config.log_file, strerror (errno));
  785. exit (1);
  786. }
  787. } else {
  788. log_file = stdout;
  789. }
  790. ids_init ();
  791. objrefs_init ();
  792. breakpoints_init ();
  793. suspend_init ();
  794. mini_get_debug_options ()->gen_seq_points = TRUE;
  795. /*
  796. * This is needed because currently we don't handle liveness info.
  797. */
  798. mini_get_debug_options ()->mdb_optimizations = TRUE;
  799. #ifndef MONO_ARCH_HAVE_CONTEXT_SET_INT_REG
  800. /* This is needed because we can't set local variables in registers yet */
  801. mono_disable_optimizations (MONO_OPT_LINEARS);
  802. #endif
  803. /*
  804. * The stack walk done from thread_interrupt () needs to be signal safe, but it
  805. * isn't, since it can call into mono_aot_find_jit_info () which is not signal
  806. * safe (#3411). So load AOT info eagerly when the debugger is running as a
  807. * workaround.
  808. */
  809. mini_get_debug_options ()->load_aot_jit_info_eagerly = TRUE;
  810. if (!agent_config.onuncaught && !agent_config.onthrow)
  811. finish_agent_init (TRUE);
  812. }
  813. /*
  814. * finish_agent_init:
  815. *
  816. * Finish the initialization of the agent. This involves connecting the transport
  817. * and starting the agent thread. This is either done at startup, or
  818. * in response to some event like an unhandled exception.
  819. */
  820. static void
  821. finish_agent_init (gboolean on_startup)
  822. {
  823. int res;
  824. if (InterlockedCompareExchange (&inited, 1, 0) == 1)
  825. return;
  826. if (agent_config.launch) {
  827. char *argv [16];
  828. // FIXME: Generated address
  829. // FIXME: Races with transport_connect ()
  830. argv [0] = agent_config.launch;
  831. argv [1] = agent_config.transport;
  832. argv [2] = agent_config.address;
  833. argv [3] = NULL;
  834. res = g_spawn_async_with_pipes (NULL, argv, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  835. if (!res) {
  836. fprintf (stderr, "Failed to execute '%s'.\n", agent_config.launch);
  837. exit (1);
  838. }
  839. }
  840. transport_connect (agent_config.address);
  841. if (!on_startup) {
  842. /* Do some which is usually done after sending the VMStart () event */
  843. vm_start_event_sent = TRUE;
  844. start_debugger_thread ();
  845. }
  846. }
  847. static void
  848. mono_debugger_agent_cleanup (void)
  849. {
  850. if (!inited)
  851. return;
  852. stop_debugger_thread ();
  853. breakpoints_cleanup ();
  854. objrefs_cleanup ();
  855. ids_cleanup ();
  856. mono_mutex_destroy (&debugger_thread_exited_mutex);
  857. mono_cond_destroy (&debugger_thread_exited_cond);
  858. }
  859. /*
  860. * SOCKET TRANSPORT
  861. */
  862. #ifndef DISABLE_SOCKET_TRANSPORT
  863. /*
  864. * recv_length:
  865. *
  866. * recv() + handle incomplete reads and EINTR
  867. */
  868. static int
  869. socket_transport_recv (void *buf, int len)
  870. {
  871. int res;
  872. int total = 0;
  873. int fd = conn_fd;
  874. int flags = 0;
  875. static gint32 last_keepalive;
  876. gint32 msecs;
  877. do {
  878. again:
  879. res = recv (fd, (char *) buf + total, len - total, flags);
  880. if (res > 0)
  881. total += res;
  882. if (agent_config.keepalive) {
  883. gboolean need_keepalive = FALSE;
  884. if (res == -1 && get_last_sock_error () == MONO_EWOULDBLOCK) {
  885. need_keepalive = TRUE;
  886. } else if (res == -1) {
  887. /* This could happen if recv () is interrupted repeatedly */
  888. msecs = mono_msec_ticks ();
  889. if (msecs - last_keepalive >= agent_config.keepalive) {
  890. need_keepalive = TRUE;
  891. last_keepalive = msecs;
  892. }
  893. }
  894. if (need_keepalive) {
  895. process_profiler_event (EVENT_KIND_KEEPALIVE, NULL);
  896. goto again;
  897. }
  898. }
  899. } while ((res > 0 && total < len) || (res == -1 && get_last_sock_error () == MONO_EINTR));
  900. return total;
  901. }
  902. #ifndef TARGET_PS3
  903. #define HAVE_GETADDRINFO 1
  904. #endif
  905. static void
  906. set_keepalive (void)
  907. {
  908. struct timeval tv;
  909. int result;
  910. if (!agent_config.keepalive || !conn_fd)
  911. return;
  912. tv.tv_sec = agent_config.keepalive / 1000;
  913. tv.tv_usec = (agent_config.keepalive % 1000) * 1000;
  914. result = setsockopt (conn_fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(struct timeval));
  915. g_assert (result >= 0);
  916. }
  917. static int
  918. socket_transport_accept (int socket_fd)
  919. {
  920. conn_fd = accept (socket_fd, NULL, NULL);
  921. if (conn_fd == -1) {
  922. fprintf (stderr, "debugger-agent: Unable to listen on %d\n", socket_fd);
  923. } else {
  924. DEBUG (1, fprintf (log_file, "Accepted connection from client, connection fd=%d.\n", conn_fd));
  925. }
  926. return conn_fd;
  927. }
  928. static gboolean
  929. socket_transport_send (void *data, int len)
  930. {
  931. int res;
  932. do {
  933. res = send (conn_fd, data, len, 0);
  934. } while (res == -1 && get_last_sock_error () == MONO_EINTR);
  935. if (res != len)
  936. return FALSE;
  937. else
  938. return TRUE;
  939. }
  940. /*
  941. * socket_transport_connect:
  942. *
  943. * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
  944. */
  945. static void
  946. socket_transport_connect (const char *address)
  947. {
  948. #ifdef HAVE_GETADDRINFO
  949. struct addrinfo hints;
  950. struct addrinfo *result, *rp;
  951. #else
  952. struct hostent *result;
  953. #endif
  954. int sfd = -1, s, res;
  955. char port_string [128];
  956. char *host;
  957. int port;
  958. if (agent_config.address) {
  959. res = parse_address (agent_config.address, &host, &port);
  960. g_assert (res == 0);
  961. } else {
  962. host = NULL;
  963. port = 0;
  964. }
  965. conn_fd = -1;
  966. listen_fd = -1;
  967. if (host) {
  968. sprintf (port_string, "%d", port);
  969. mono_network_init ();
  970. /* Obtain address(es) matching host/port */
  971. #ifdef HAVE_GETADDRINFO
  972. memset (&hints, 0, sizeof (struct addrinfo));
  973. hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
  974. hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
  975. hints.ai_flags = 0;
  976. hints.ai_protocol = 0; /* Any protocol */
  977. s = getaddrinfo (host, port_string, &hints, &result);
  978. if (s != 0) {
  979. fprintf (stderr, "debugger-agent: Unable to resolve %s:%d: %s\n", host, port, gai_strerror (s));
  980. exit (1);
  981. }
  982. #else
  983. /* The PS3 doesn't even have _r or hstrerror () */
  984. result = gethostbyname (host);
  985. if (!result) {
  986. fprintf (stderr, "debugger-agent: Unable to resolve %s:%d: %d\n", host, port, h_errno);
  987. }
  988. #endif
  989. }
  990. if (agent_config.server) {
  991. #ifdef HAVE_GETADDRINFO
  992. /* Wait for a connection */
  993. if (!host) {
  994. struct sockaddr_in addr;
  995. socklen_t addrlen;
  996. /* No address, generate one */
  997. sfd = socket (AF_INET, SOCK_STREAM, 0);
  998. g_assert (sfd);
  999. /* This will bind the socket to a random port */
  1000. res = listen (sfd, 16);
  1001. if (res == -1) {
  1002. fprintf (stderr, "debugger-agent: Unable to setup listening socket: %s\n", strerror (get_last_sock_error ()));
  1003. exit (1);
  1004. }
  1005. listen_fd = sfd;
  1006. addrlen = sizeof (addr);
  1007. memset (&addr, 0, sizeof (addr));
  1008. res = getsockname (sfd, (struct sockaddr*)&addr, &addrlen);
  1009. g_assert (res == 0);
  1010. host = (char*)"127.0.0.1";
  1011. port = ntohs (addr.sin_port);
  1012. /* Emit the address to stdout */
  1013. /* FIXME: Should print another interface, not localhost */
  1014. printf ("%s:%d\n", host, port);
  1015. } else {
  1016. /* Listen on the provided address */
  1017. for (rp = result; rp != NULL; rp = rp->ai_next) {
  1018. int n = 1;
  1019. sfd = socket (rp->ai_family, rp->ai_socktype,
  1020. rp->ai_protocol);
  1021. if (sfd == -1)
  1022. continue;
  1023. if (setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
  1024. continue;
  1025. res = bind (sfd, rp->ai_addr, rp->ai_addrlen);
  1026. if (res == -1)
  1027. continue;
  1028. res = listen (sfd, 16);
  1029. if (res == -1)
  1030. continue;
  1031. listen_fd = sfd;
  1032. break;
  1033. }
  1034. #ifndef HOST_WIN32
  1035. /*
  1036. * this function is not present on win2000 which we still support, and the
  1037. * workaround described here:
  1038. * http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx
  1039. * only works with MSVC.
  1040. */
  1041. #ifdef HAVE_GETADDRINFO
  1042. freeaddrinfo (result);
  1043. #endif
  1044. #endif
  1045. }
  1046. if (agent_config.defer)
  1047. return;
  1048. DEBUG (1, fprintf (log_file, "Listening on %s:%d (timeout=%d ms)...\n", host, port, agent_config.timeout));
  1049. if (agent_config.timeout) {
  1050. fd_set readfds;
  1051. struct timeval tv;
  1052. tv.tv_sec = 0;
  1053. tv.tv_usec = agent_config.timeout * 1000;
  1054. FD_ZERO (&readfds);
  1055. FD_SET (sfd, &readfds);
  1056. res = select (sfd + 1, &readfds, NULL, NULL, &tv);
  1057. if (res == 0) {
  1058. fprintf (stderr, "debugger-agent: Timed out waiting to connect.\n");
  1059. exit (1);
  1060. }
  1061. }
  1062. conn_fd = socket_transport_accept (sfd);
  1063. if (conn_fd == -1)
  1064. exit (1);
  1065. DEBUG (1, fprintf (log_file, "Accepted connection from client, socket fd=%d.\n", conn_fd));
  1066. #else
  1067. NOT_IMPLEMENTED;
  1068. #endif /* HAVE_GETADDRINFO */
  1069. } else {
  1070. /* Connect to the specified address */
  1071. #ifdef HAVE_GETADDRINFO
  1072. /* FIXME: Respect the timeout */
  1073. for (rp = result; rp != NULL; rp = rp->ai_next) {
  1074. sfd = socket (rp->ai_family, rp->ai_socktype,
  1075. rp->ai_protocol);
  1076. if (sfd == -1)
  1077. continue;
  1078. if (connect (sfd, rp->ai_addr, rp->ai_addrlen) != -1)
  1079. break; /* Success */
  1080. close (sfd);
  1081. }
  1082. if (rp == 0) {
  1083. fprintf (stderr, "debugger-agent: Unable to connect to %s:%d\n", host, port);
  1084. exit (1);
  1085. }
  1086. #else
  1087. sfd = socket (result->h_addrtype, SOCK_STREAM, 0);
  1088. if (sfd == -1)
  1089. g_assert_not_reached ();
  1090. res = connect (sfd, (void*)result->h_addr_list [0], result->h_length);
  1091. if (res == -1)
  1092. g_assert_not_reached ();
  1093. #endif
  1094. conn_fd = sfd;
  1095. #ifndef HOST_WIN32
  1096. /* See the comment above */
  1097. #ifdef HAVE_GETADDRINFO
  1098. freeaddrinfo (result);
  1099. #endif
  1100. #endif
  1101. }
  1102. if (!transport_handshake ())
  1103. exit (1);
  1104. }
  1105. static void
  1106. socket_transport_close1 (void)
  1107. {
  1108. /* This will interrupt the agent thread */
  1109. /* Close the read part only so it can still send back replies */
  1110. /* Also shut down the connection listener so that we can exit normally */
  1111. #ifdef HOST_WIN32
  1112. /* SD_RECEIVE doesn't break the recv in the debugger thread */
  1113. shutdown (conn_fd, SD_BOTH);
  1114. shutdown (listen_fd, SD_BOTH);
  1115. closesocket (listen_fd);
  1116. #else
  1117. shutdown (conn_fd, SHUT_RD);
  1118. shutdown (listen_fd, SHUT_RDWR);
  1119. close (listen_fd);
  1120. #endif
  1121. }
  1122. static void
  1123. socket_transport_close2 (void)
  1124. {
  1125. #ifdef HOST_WIN32
  1126. shutdown (conn_fd, SD_BOTH);
  1127. #else
  1128. shutdown (conn_fd, SHUT_RDWR);
  1129. #endif
  1130. }
  1131. static void
  1132. register_socket_transport (void)
  1133. {
  1134. DebuggerTransport trans;
  1135. trans.name = "dt_socket";
  1136. trans.connect = socket_transport_connect;
  1137. trans.close1 = socket_transport_close1;
  1138. trans.close2 = socket_transport_close2;
  1139. trans.send = socket_transport_send;
  1140. trans.recv = socket_transport_recv;
  1141. register_transport (&trans);
  1142. }
  1143. #endif /* DISABLE_SOCKET_TRANSPORT */
  1144. /*
  1145. * TRANSPORT CODE
  1146. */
  1147. #define MAX_TRANSPORTS 16
  1148. static DebuggerTransport *transport;
  1149. static DebuggerTransport transports [MAX_TRANSPORTS];
  1150. static int ntransports;
  1151. void
  1152. mono_debugger_agent_register_transport (DebuggerTransport *trans);
  1153. void
  1154. mono_debugger_agent_register_transport (DebuggerTransport *trans)
  1155. {
  1156. register_transport (trans);
  1157. }
  1158. static void
  1159. register_transport (DebuggerTransport *trans)
  1160. {
  1161. g_assert (ntransports < MAX_TRANSPORTS);
  1162. memcpy (&transports [ntransports], trans, sizeof (DebuggerTransport));
  1163. ntransports ++;
  1164. }
  1165. static void
  1166. transport_init (void)
  1167. {
  1168. int i;
  1169. #ifndef DISABLE_SOCKET_TRANSPORT
  1170. register_socket_transport ();
  1171. #endif
  1172. for (i = 0; i < ntransports; ++i) {
  1173. if (!strcmp (agent_config.transport, transports [i].name))
  1174. break;
  1175. }
  1176. if (i == ntransports) {
  1177. fprintf (stderr, "debugger-agent: The supported values for the 'transport' option are: ");
  1178. for (i = 0; i < ntransports; ++i)
  1179. fprintf (stderr, "%s'%s'", i > 0 ? ", " : "", transports [i].name);
  1180. fprintf (stderr, "\n");
  1181. exit (1);
  1182. }
  1183. transport = &transports [i];
  1184. }
  1185. void
  1186. transport_connect (const char *address)
  1187. {
  1188. transport->connect (address);
  1189. }
  1190. static void
  1191. transport_close1 (void)
  1192. {
  1193. transport->close1 ();
  1194. }
  1195. static void
  1196. transport_close2 (void)
  1197. {
  1198. transport->close2 ();
  1199. }
  1200. static int
  1201. transport_send (void *buf, int len)
  1202. {
  1203. return transport->send (buf, len);
  1204. }
  1205. static int
  1206. transport_recv (void *buf, int len)
  1207. {
  1208. return transport->recv (buf, len);
  1209. }
  1210. gboolean
  1211. mono_debugger_agent_transport_handshake (void)
  1212. {
  1213. return transport_handshake ();
  1214. }
  1215. static gboolean
  1216. transport_handshake (void)
  1217. {
  1218. char handshake_msg [128];
  1219. guint8 buf [128];
  1220. int res;
  1221. disconnected = TRUE;
  1222. /* Write handshake message */
  1223. sprintf (handshake_msg, "DWP-Handshake");
  1224. do {
  1225. res = transport_send (handshake_msg, strlen (handshake_msg));
  1226. } while (res == -1 && get_last_sock_error () == MONO_EINTR);
  1227. g_assert (res != -1);
  1228. /* Read answer */
  1229. res = transport_recv (buf, strlen (handshake_msg));
  1230. if ((res != strlen (handshake_msg)) || (memcmp (buf, handshake_msg, strlen (handshake_msg) != 0))) {
  1231. fprintf (stderr, "debugger-agent: DWP handshake failed.\n");
  1232. return FALSE;
  1233. }
  1234. /*
  1235. * To support older clients, the client sends its protocol version after connecting
  1236. * using a command. Until that is received, default to our protocol version.
  1237. */
  1238. major_version = MAJOR_VERSION;
  1239. minor_version = MINOR_VERSION;
  1240. protocol_version_set = FALSE;
  1241. #ifndef DISABLE_SOCKET_TRANSPORT
  1242. // FIXME: Move this somewhere else
  1243. /*
  1244. * Set TCP_NODELAY on the socket so the client receives events/command
  1245. * results immediately.
  1246. */
  1247. if (conn_fd) {
  1248. int flag = 1;
  1249. int result = setsockopt (conn_fd,
  1250. IPPROTO_TCP,
  1251. TCP_NODELAY,
  1252. (char *) &flag,
  1253. sizeof(int));
  1254. g_assert (result >= 0);
  1255. }
  1256. set_keepalive ();
  1257. #endif
  1258. disconnected = FALSE;
  1259. return TRUE;
  1260. }
  1261. static void
  1262. stop_debugger_thread (void)
  1263. {
  1264. if (!inited)
  1265. return;
  1266. transport_close1 ();
  1267. /*
  1268. * Wait for the thread to exit.
  1269. *
  1270. * If we continue with the shutdown without waiting for it, then the client might
  1271. * not receive an answer to its last command like a resume.
  1272. * The WaitForSingleObject infrastructure doesn't seem to work during shutdown, so
  1273. * use pthreads.
  1274. */
  1275. //WaitForSingleObject (debugger_thread_handle, INFINITE);
  1276. if (GetCurrentThreadId () != debugger_thread_id) {
  1277. do {
  1278. mono_mutex_lock (&debugger_thread_exited_mutex);
  1279. if (!debugger_thread_exited) {
  1280. #ifdef HOST_WIN32
  1281. if (WAIT_TIMEOUT == WaitForSingleObject(debugger_thread_exited_cond, 0)) {
  1282. mono_mutex_unlock (&debugger_thread_exited_mutex);
  1283. Sleep(1);
  1284. mono_mutex_lock (&debugger_thread_exited_mutex);
  1285. }
  1286. #else
  1287. mono_cond_wait (&debugger_thread_exited_cond, &debugger_thread_exited_mutex);
  1288. #endif
  1289. }
  1290. mono_mutex_unlock (&debugger_thread_exited_mutex);
  1291. } while (!debugger_thread_exited);
  1292. }
  1293. transport_close2 ();
  1294. }
  1295. static void
  1296. start_debugger_thread (void)
  1297. {
  1298. gsize tid;
  1299. debugger_thread_handle = mono_create_thread (NULL, 0, debugger_thread, NULL, 0, &tid);
  1300. g_assert (debugger_thread_handle);
  1301. }
  1302. /*
  1303. * Functions to decode protocol data
  1304. */
  1305. static inline int
  1306. decode_byte (guint8 *buf, guint8 **endbuf, guint8 *limit)
  1307. {
  1308. *endbuf = buf + 1;
  1309. g_assert (*endbuf <= limit);
  1310. return buf [0];
  1311. }
  1312. static inline int
  1313. decode_int (guint8 *buf, guint8 **endbuf, guint8 *limit)
  1314. {
  1315. *endbuf = buf + 4;
  1316. g_assert (*endbuf <= limit);
  1317. return (((int)buf [0]) << 24) | (((int)buf [1]) << 16) | (((int)buf [2]) << 8) | (((int)buf [3]) << 0);
  1318. }
  1319. static inline gint64
  1320. decode_long (guint8 *buf, guint8 **endbuf, guint8 *limit)
  1321. {
  1322. guint32 high = decode_int (buf, &buf, limit);
  1323. guint32 low = decode_int (buf, &buf, limit);
  1324. *endbuf = buf;
  1325. return ((((guint64)high) << 32) | ((guint64)low));
  1326. }
  1327. static inline int
  1328. decode_id (guint8 *buf, guint8 **endbuf, guint8 *limit)
  1329. {
  1330. return decode_int (buf, endbuf, limit);
  1331. }
  1332. static inline char*
  1333. decode_string (guint8 *buf, guint8 **endbuf, guint8 *limit)
  1334. {
  1335. int len = decode_int (buf, &buf, limit);
  1336. char *s;
  1337. if (len < 0) {
  1338. *endbuf = buf;
  1339. return NULL;
  1340. }
  1341. s = g_malloc (len + 1);
  1342. g_assert (s);
  1343. memcpy (s, buf, len);
  1344. s [len] = '\0';
  1345. buf += len;
  1346. *endbuf = buf;
  1347. return s;
  1348. }
  1349. /*
  1350. * Functions to encode protocol data
  1351. */
  1352. typedef struct {
  1353. guint8 *buf, *p, *end;
  1354. } Buffer;
  1355. static inline void
  1356. buffer_init (Buffer *buf, int size)
  1357. {
  1358. buf->buf = g_malloc (size);
  1359. buf->p = buf->buf;
  1360. buf->end = buf->buf + size;
  1361. }
  1362. static inline void
  1363. buffer_make_room (Buffer *buf, int size)
  1364. {
  1365. if (buf->end - buf->p < size) {
  1366. int new_size = buf->end - buf->buf + size + 32;
  1367. guint8 *p = g_realloc (buf->buf, new_size);
  1368. size = buf->p - buf->buf;
  1369. buf->buf = p;
  1370. buf->p = p + size;
  1371. buf->end = buf->buf + new_size;
  1372. }
  1373. }
  1374. static inline void
  1375. buffer_add_byte (Buffer *buf, guint8 val)
  1376. {
  1377. buffer_make_room (buf, 1);
  1378. buf->p [0] = val;
  1379. buf->p++;
  1380. }
  1381. static inline void
  1382. buffer_add_short (Buffer *buf, guint32 val)
  1383. {
  1384. buffer_make_room (buf, 2);
  1385. buf->p [0] = (val >> 8) & 0xff;
  1386. buf->p [1] = (val >> 0) & 0xff;
  1387. buf->p += 2;
  1388. }
  1389. static inline void
  1390. buffer_add_int (Buffer *buf, guint32 val)
  1391. {
  1392. buffer_make_room (buf, 4);
  1393. buf->p [0] = (val >> 24) & 0xff;
  1394. buf->p [1] = (val >> 16) & 0xff;
  1395. buf->p [2] = (val >> 8) & 0xff;
  1396. buf->p [3] = (val >> 0) & 0xff;
  1397. buf->p += 4;
  1398. }
  1399. static inline void
  1400. buffer_add_long (Buffer *buf, guint64 l)
  1401. {
  1402. buffer_add_int (buf, (l >> 32) & 0xffffffff);
  1403. buffer_add_int (buf, (l >> 0) & 0xffffffff);
  1404. }
  1405. static inline void
  1406. buffer_add_id (Buffer *buf, int id)
  1407. {
  1408. buffer_add_int (buf, (guint64)id);
  1409. }
  1410. static inline void
  1411. buffer_add_data (Buffer *buf, guint8 *data, int len)
  1412. {
  1413. buffer_make_room (buf, len);
  1414. memcpy (buf->p, data, len);
  1415. buf->p += len;
  1416. }
  1417. static inline void
  1418. buffer_add_string (Buffer *buf, const char *str)
  1419. {
  1420. int len;
  1421. if (str == NULL) {
  1422. buffer_add_int (buf, 0);
  1423. } else {
  1424. len = strlen (str);
  1425. buffer_add_int (buf, len);
  1426. buffer_add_data (buf, (guint8*)str, len);
  1427. }
  1428. }
  1429. static inline void
  1430. buffer_free (Buffer *buf)
  1431. {
  1432. g_free (buf->buf);
  1433. }
  1434. static gboolean
  1435. send_packet (int command_set, int command, Buffer *data)
  1436. {
  1437. Buffer buf;
  1438. int len, id;
  1439. gboolean res;
  1440. id = InterlockedIncrement (&packet_id);
  1441. len = data->p - data->buf + 11;
  1442. buffer_init (&buf, len);
  1443. buffer_add_int (&buf, len);
  1444. buffer_add_int (&buf, id);
  1445. buffer_add_byte (&buf, 0); /* flags */
  1446. buffer_add_byte (&buf, command_set);
  1447. buffer_add_byte (&buf, command);
  1448. memcpy (buf.buf + 11, data->buf, data->p - data->buf);
  1449. res = transport_send (buf.buf, len);
  1450. buffer_free (&buf);
  1451. return res;
  1452. }
  1453. static gboolean
  1454. send_reply_packet (int id, int error, Buffer *data)
  1455. {
  1456. Buffer buf;
  1457. int len;
  1458. gboolean res;
  1459. len = data->p - data->buf + 11;
  1460. buffer_init (&buf, len);
  1461. buffer_add_int (&buf, len);
  1462. buffer_add_int (&buf, id);
  1463. buffer_add_byte (&buf, 0x80); /* flags */
  1464. buffer_add_byte (&buf, (error >> 8) & 0xff);
  1465. buffer_add_byte (&buf, error);
  1466. memcpy (buf.buf + 11, data->buf, data->p - data->buf);
  1467. res = transport_send (buf.buf, len);
  1468. buffer_free (&buf);
  1469. return res;
  1470. }
  1471. /*
  1472. * OBJECT IDS
  1473. */
  1474. /*
  1475. * Represents an object accessible by the debugger client.
  1476. */
  1477. typedef struct {
  1478. /* Unique id used in the wire protocol to refer to objects */
  1479. int id;
  1480. /*
  1481. * A weakref gc handle pointing to the object. The gc handle is used to
  1482. * detect if the object was garbage collected.
  1483. */
  1484. guint32 handle;
  1485. } ObjRef;
  1486. /* Maps objid -> ObjRef */
  1487. static GHashTable *objrefs;
  1488. static void
  1489. free_objref (gpointer value)
  1490. {
  1491. ObjRef *o = value;
  1492. mono_gchandle_free (o->handle);
  1493. g_free (o);
  1494. }
  1495. static void
  1496. objrefs_init (void)
  1497. {
  1498. objrefs = g_hash_table_new_full (NULL, NULL, NULL, free_objref);
  1499. }
  1500. static void
  1501. objrefs_cleanup (void)
  1502. {
  1503. g_hash_table_destroy (objrefs);
  1504. objrefs = NULL;
  1505. }
  1506. static GHashTable *obj_to_objref;
  1507. static MonoGHashTable *suspended_objs;
  1508. /*
  1509. * Return an ObjRef for OBJ.
  1510. */
  1511. static ObjRef*
  1512. get_objref (MonoObject *obj)
  1513. {
  1514. ObjRef *ref;
  1515. GSList *reflist = NULL, *l;
  1516. int hash = 0;
  1517. if (obj == NULL)
  1518. return 0;
  1519. mono_loader_lock ();
  1520. if (!obj_to_objref) {
  1521. obj_to_objref = g_hash_table_new (NULL, NULL);
  1522. suspended_objs = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC);
  1523. MONO_GC_REGISTER_ROOT_FIXED (suspended_objs);
  1524. }
  1525. if (suspend_count) {
  1526. /*
  1527. * Have to keep object refs created during suspensions alive for the duration of the suspension, so GCs during invokes don't collect them.
  1528. */
  1529. mono_g_hash_table_insert (suspended_objs, obj, NULL);
  1530. }
  1531. /* FIXME: The tables can grow indefinitely */
  1532. if (mono_gc_is_moving ()) {
  1533. /*
  1534. * Objects can move, so use a hash table mapping hash codes to lists of
  1535. * ObjRef structures.
  1536. */
  1537. hash = mono_object_hash (obj);
  1538. reflist = g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (hash));
  1539. for (l = reflist; l; l = l->next) {
  1540. ref = l->data;
  1541. if (ref && mono_gchandle_get_target (ref->handle) == obj) {
  1542. mono_loader_unlock ();
  1543. return ref;
  1544. }
  1545. }
  1546. } else {
  1547. /* Use a hash table with masked pointers to internalize object references */
  1548. ref = g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)));
  1549. /* ref might refer to a different object with the same addr which was GCd */
  1550. if (ref && mono_gchandle_get_target (ref->handle) == obj) {
  1551. mono_loader_unlock ();
  1552. return ref;
  1553. }
  1554. }
  1555. ref = g_new0 (ObjRef, 1);
  1556. ref->id = InterlockedIncrement (&objref_id);
  1557. ref->handle = mono_gchandle_new_weakref (obj, FALSE);
  1558. g_hash_table_insert (objrefs, GINT_TO_POINTER (ref->id), ref);
  1559. if (mono_gc_is_moving ()) {
  1560. reflist = g_slist_append (reflist, ref);
  1561. g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (hash), reflist);
  1562. } else {
  1563. g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)), ref);
  1564. }
  1565. mono_loader_unlock ();
  1566. return ref;
  1567. }
  1568. static gboolean
  1569. true_pred (gpointer key, gpointer value, gpointer user_data)
  1570. {
  1571. return TRUE;
  1572. }
  1573. static void
  1574. clear_suspended_objs (void)
  1575. {
  1576. mono_loader_lock ();
  1577. mono_g_hash_table_foreach_remove (suspended_objs, true_pred, NULL);
  1578. mono_loader_unlock ();
  1579. }
  1580. static inline int
  1581. get_objid (MonoObject *obj)
  1582. {
  1583. return get_objref (obj)->id;
  1584. }
  1585. /*
  1586. * Set OBJ to the object identified by OBJID.
  1587. * Returns 0 or an error code if OBJID is invalid or the object has been garbage
  1588. * collected.
  1589. */
  1590. static ErrorCode
  1591. get_object_allow_null (int objid, MonoObject **obj)
  1592. {
  1593. ObjRef *ref;
  1594. if (objid == 0) {
  1595. *obj = NULL;
  1596. return 0;
  1597. }
  1598. if (!objrefs)
  1599. return ERR_INVALID_OBJECT;
  1600. mono_loader_lock ();
  1601. ref = g_hash_table_lookup (objrefs, GINT_TO_POINTER (objid));
  1602. if (ref) {
  1603. *obj = mono_gchandle_get_target (ref->handle);
  1604. mono_loader_unlock ();
  1605. if (!(*obj))
  1606. return ERR_INVALID_OBJECT;
  1607. return 0;
  1608. } else {
  1609. mono_loader_unlock ();
  1610. return ERR_INVALID_OBJECT;
  1611. }
  1612. }
  1613. static ErrorCode
  1614. get_object (int objid, MonoObject **obj)
  1615. {
  1616. int err = get_object_allow_null (objid, obj);
  1617. if (err)
  1618. return err;
  1619. if (!(*obj))
  1620. return ERR_INVALID_OBJECT;
  1621. return 0;
  1622. }
  1623. static inline int
  1624. decode_objid (guint8 *buf, guint8 **endbuf, guint8 *limit)
  1625. {
  1626. return decode_id (buf, endbuf, limit);
  1627. }
  1628. static inline void
  1629. buffer_add_objid (Buffer *buf, MonoObject *o)
  1630. {
  1631. buffer_add_id (buf, get_objid (o));
  1632. }
  1633. /*
  1634. * IDS
  1635. */
  1636. typedef enum {
  1637. ID_ASSEMBLY = 0,
  1638. ID_MODULE = 1,
  1639. ID_TYPE = 2,
  1640. ID_METHOD = 3,
  1641. ID_FIELD = 4,
  1642. ID_DOMAIN = 5,
  1643. ID_PROPERTY = 6,
  1644. ID_NUM
  1645. } IdType;
  1646. /*
  1647. * Represents a runtime structure accessible to the debugger client
  1648. */
  1649. typedef struct {
  1650. /* Unique id used in the wire protocol */
  1651. int id;
  1652. /* Domain of the runtime structure, NULL if the domain was unloaded */
  1653. MonoDomain *domain;
  1654. union {
  1655. gpointer val;
  1656. MonoClass *klass;
  1657. MonoMethod *method;
  1658. MonoImage *image;
  1659. MonoAssembly *assembly;
  1660. MonoClassField *field;
  1661. MonoDomain *domain;
  1662. MonoProperty *property;
  1663. } data;
  1664. } Id;
  1665. typedef struct {
  1666. /* Maps runtime structure -> Id */
  1667. GHashTable *val_to_id [ID_NUM];
  1668. /* Classes whose class load event has been sent */
  1669. GHashTable *loaded_classes;
  1670. /* Maps MonoClass->GPtrArray of file names */
  1671. GHashTable *source_files;
  1672. /* Maps source file basename -> GSList of classes */
  1673. GHashTable *source_file_to_class;
  1674. /* Same with ignore-case */
  1675. GHashTable *source_file_to_class_ignorecase;
  1676. } AgentDomainInfo;
  1677. /* Maps id -> Id */
  1678. static GPtrArray *ids [ID_NUM];
  1679. static void
  1680. ids_init (void)
  1681. {
  1682. int i;
  1683. for (i = 0; i < ID_NUM; ++i)
  1684. ids [i] = g_ptr_array_new ();
  1685. }
  1686. static void
  1687. ids_cleanup (void)
  1688. {
  1689. int i, j;
  1690. for (i = 0; i < ID_NUM; ++i) {
  1691. if (ids [i]) {
  1692. for (j = 0; j < ids [i]->len; ++j)
  1693. g_free (g_ptr_array_index (ids [i], j));
  1694. g_ptr_array_free (ids [i], TRUE);
  1695. }
  1696. ids [i] = NULL;
  1697. }
  1698. }
  1699. void
  1700. mono_debugger_agent_free_domain_info (MonoDomain *domain)
  1701. {
  1702. AgentDomainInfo *info = domain_jit_info (domain)->agent_info;
  1703. int i, j;
  1704. GHashTableIter iter;
  1705. GPtrArray *file_names;
  1706. char *basename;
  1707. GSList *l;
  1708. if (info) {
  1709. for (i = 0; i < ID_NUM; ++i)
  1710. if (info->val_to_id [i])
  1711. g_hash_table_destroy (info->val_to_id [i]);
  1712. g_hash_table_destroy (info->loaded_classes);
  1713. g_hash_table_iter_init (&iter, info->source_files);
  1714. while (g_hash_table_iter_next (&iter, NULL, (void**)&file_names)) {
  1715. for (i = 0; i < file_names->len; ++i)
  1716. g_free (g_ptr_array_index (file_names, i));
  1717. g_ptr_array_free (file_names, TRUE);
  1718. }
  1719. g_hash_table_iter_init (&iter, info->source_file_to_class);
  1720. while (g_hash_table_iter_next (&iter, (void**)&basename, (void**)&l)) {
  1721. g_free (basename);
  1722. g_slist_free (l);
  1723. }
  1724. g_hash_table_iter_init (&iter, info->source_file_to_class_ignorecase);
  1725. while (g_hash_table_iter_next (&iter, (void**)&basename, (void**)&l)) {
  1726. g_free (basename);
  1727. g_slist_free (l);
  1728. }
  1729. g_free (info);
  1730. }
  1731. domain_jit_info (domain)->agent_info = NULL;
  1732. /* Clear ids referencing structures in the domain */
  1733. for (i = 0; i < ID_NUM; ++i) {
  1734. if (ids [i]) {
  1735. for (j = 0; j < ids [i]->len; ++j) {
  1736. Id *id = g_ptr_array_index (ids [i], j);
  1737. if (id->domain == do

Large files files are truncated, but you can click here to view the full file