1 /*
2 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include "util.h"
27 #include "transport.h"
28 #include "debugLoop.h"
29 #include "sys.h"
30
31 static jdwpTransportEnv *transport;
32 static jrawMonitorID listenerLock;
33 static jrawMonitorID sendLock;
34
35 /*
36 * data structure used for passing transport info from thread to thread
37 */
38 typedef struct TransportInfo {
39 char *name;
40 jdwpTransportEnv *transport;
41 char *address;
42 long timeout;
43 } TransportInfo;
44
45 static struct jdwpTransportCallback callback = {jvmtiAllocate, jvmtiDeallocate};
46
47 /*
48 * Print the last transport error
49 */
50 static void
printLastError(jdwpTransportEnv * t,jdwpTransportError err)51 printLastError(jdwpTransportEnv *t, jdwpTransportError err)
52 {
53 char *msg;
54 jbyte *utf8msg;
55 jdwpTransportError rv;
56
57 msg = NULL;
58 utf8msg = NULL;
59 rv = (*t)->GetLastError(t, &msg); /* This is a platform encoded string */
60 if ( msg != NULL ) {
61 int len;
62 int maxlen;
63
64 /* Convert this string to UTF8 */
65 len = (int)strlen(msg);
66 maxlen = len+len/2+2; /* Should allow for plenty of room */
67 utf8msg = (jbyte*)jvmtiAllocate(maxlen+1);
68 (void)(gdata->npt->utf8FromPlatform)(gdata->npt->utf,
69 msg, len, utf8msg, maxlen);
70 utf8msg[maxlen] = 0;
71 }
72 if (rv == JDWPTRANSPORT_ERROR_NONE) {
73 ERROR_MESSAGE(("transport error %d: %s",err, utf8msg));
74 } else if ( msg!=NULL ) {
75 ERROR_MESSAGE(("transport error %d: %s",err, utf8msg));
76 } else {
77 ERROR_MESSAGE(("transport error %d: %s",err, "UNKNOWN"));
78 }
79 jvmtiDeallocate(msg);
80 jvmtiDeallocate(utf8msg);
81 }
82
83 /* Find OnLoad symbol */
84 static jdwpTransport_OnLoad_t
findTransportOnLoad(void * handle)85 findTransportOnLoad(void *handle)
86 {
87 jdwpTransport_OnLoad_t onLoad;
88
89 onLoad = (jdwpTransport_OnLoad_t)NULL;
90 if (handle == NULL) {
91 return onLoad;
92 }
93 onLoad = (jdwpTransport_OnLoad_t)
94 dbgsysFindLibraryEntry(handle, "jdwpTransport_OnLoad");
95 return onLoad;
96 }
97
98 /* Load transport library (directory=="" means do system search) */
99 static void *
loadTransportLibrary(const char * libdir,const char * name)100 loadTransportLibrary(const char *libdir, const char *name)
101 {
102 void *handle;
103 char libname[MAXPATHLEN+2];
104 char buf[MAXPATHLEN*2+100];
105 const char *plibdir;
106
107 /* Convert libdir from UTF-8 to platform encoding */
108 plibdir = NULL;
109 if ( libdir != NULL ) {
110 int len;
111
112 len = (int)strlen(libdir);
113 (void)(gdata->npt->utf8ToPlatform)(gdata->npt->utf,
114 (jbyte*)libdir, len, buf, (int)sizeof(buf));
115 plibdir = buf;
116 }
117
118 /* Construct library name (simple name or full path) */
119 dbgsysBuildLibName(libname, sizeof(libname), plibdir, name);
120 if (strlen(libname) == 0) {
121 return NULL;
122 }
123
124 /* dlopen (unix) / LoadLibrary (windows) the transport library */
125 handle = dbgsysLoadLibrary(libname, buf, sizeof(buf));
126 return handle;
127 }
128
129 /*
130 * loadTransport() is adapted from loadJVMHelperLib() in
131 * JDK 1.2 javai.c v1.61
132 */
133 static jdwpError
loadTransport(const char * name,jdwpTransportEnv ** transportPtr)134 loadTransport(const char *name, jdwpTransportEnv **transportPtr)
135 {
136 JNIEnv *env;
137 jdwpTransport_OnLoad_t onLoad;
138 void *handle;
139 const char *libdir;
140
141 /* Make sure library name is not empty */
142 if (name == NULL) {
143 ERROR_MESSAGE(("library name is empty"));
144 return JDWP_ERROR(TRANSPORT_LOAD);
145 }
146
147 /* First, look in sun.boot.library.path. This should find the standard
148 * dt_socket and dt_shmem transport libraries, or any library
149 * that was delivered with the J2SE.
150 * Note: Since 6819213 fixed, Java property sun.boot.library.path can
151 * contain multiple paths. Dll_dir is the first entry and
152 * -Dsun.boot.library.path entries are appended.
153 */
154 libdir = gdata->property_sun_boot_library_path;
155 if (libdir == NULL) {
156 ERROR_MESSAGE(("Java property sun.boot.library.path is not set"));
157 return JDWP_ERROR(TRANSPORT_LOAD);
158 }
159 handle = loadTransportLibrary(libdir, name);
160 if (handle == NULL) {
161 /* Second, look along the path used by the native dlopen/LoadLibrary
162 * functions. This should effectively try and load the simple
163 * library name, which will cause the default system library
164 * search technique to happen.
165 * We should only reach here if the transport library wasn't found
166 * in the J2SE directory, e.g. it's a custom transport library
167 * not installed in the J2SE like dt_socket and dt_shmem is.
168 *
169 * Note: Why not use java.library.path? Several reasons:
170 * a) This matches existing agentlib search
171 * b) These are technically not JNI libraries
172 */
173 handle = loadTransportLibrary("", name);
174 }
175
176 /* See if a library was found with this name */
177 if (handle == NULL) {
178 ERROR_MESSAGE(("transport library not found: %s", name));
179 return JDWP_ERROR(TRANSPORT_LOAD);
180 }
181
182 /* Find the onLoad address */
183 onLoad = findTransportOnLoad(handle);
184 if (onLoad == NULL) {
185 ERROR_MESSAGE(("transport library missing onLoad entry: %s", name));
186 return JDWP_ERROR(TRANSPORT_LOAD);
187 }
188
189 /* Get transport interface */
190 env = getEnv();
191 if ( env != NULL ) {
192 jdwpTransportEnv *t;
193 JavaVM *jvm;
194 jint ver;
195
196 JNI_FUNC_PTR(env,GetJavaVM)(env, &jvm);
197 ver = (*onLoad)(jvm, &callback, JDWPTRANSPORT_VERSION_1_0, &t);
198 if (ver != JNI_OK) {
199 switch (ver) {
200 case JNI_ENOMEM :
201 ERROR_MESSAGE(("insufficient memory to complete initialization"));
202 break;
203
204 case JNI_EVERSION :
205 ERROR_MESSAGE(("transport doesn't recognize version %x",
206 JDWPTRANSPORT_VERSION_1_0));
207 break;
208
209 case JNI_EEXIST :
210 ERROR_MESSAGE(("transport doesn't support multiple environments"));
211 break;
212
213 default:
214 ERROR_MESSAGE(("unrecognized error %d from transport", ver));
215 break;
216 }
217
218 return JDWP_ERROR(TRANSPORT_INIT);
219 }
220 *transportPtr = t;
221 } else {
222 return JDWP_ERROR(TRANSPORT_LOAD);
223 }
224
225 return JDWP_ERROR(NONE);
226 }
227
228 static void
connectionInitiated(jdwpTransportEnv * t)229 connectionInitiated(jdwpTransportEnv *t)
230 {
231 jint isValid = JNI_FALSE;
232
233 debugMonitorEnter(listenerLock);
234
235 /*
236 * Don't allow a connection until initialization is complete
237 */
238 debugInit_waitInitComplete();
239
240 /* Are we the first transport to get a connection? */
241
242 if (transport == NULL) {
243 transport = t;
244 isValid = JNI_TRUE;
245 } else {
246 if (transport == t) {
247 /* connected with the same transport as before */
248 isValid = JNI_TRUE;
249 } else {
250 /*
251 * Another transport got a connection - multiple transports
252 * not fully supported yet so shouldn't get here.
253 */
254 (*t)->Close(t);
255 JDI_ASSERT(JNI_FALSE);
256 }
257 }
258
259 if (isValid) {
260 debugMonitorNotifyAll(listenerLock);
261 }
262
263 debugMonitorExit(listenerLock);
264
265 if (isValid) {
266 debugLoop_run();
267 }
268
269 }
270
271 /*
272 * Set the transport property (sun.jdwp.listenerAddress) to the
273 * specified value.
274 */
275 static void
setTransportProperty(JNIEnv * env,char * value)276 setTransportProperty(JNIEnv* env, char* value) {
277 char* prop_value = (value == NULL) ? "" : value;
278 setAgentPropertyValue(env, "sun.jdwp.listenerAddress", prop_value);
279 }
280
281 void
transport_waitForConnection(void)282 transport_waitForConnection(void)
283 {
284 /*
285 * If the VM is suspended on debugger initialization, we wait
286 * for a connection before continuing. This ensures that all
287 * events are delivered to the debugger. (We might as well do this
288 * this since the VM won't continue until a remote debugger attaches
289 * and resumes it.) If not suspending on initialization, we must
290 * just drop any packets (i.e. events) so that the VM can continue
291 * to run. The debugger may not attach until much later.
292 */
293 if (debugInit_suspendOnInit()) {
294 debugMonitorEnter(listenerLock);
295 while (transport == NULL) {
296 debugMonitorWait(listenerLock);
297 }
298 debugMonitorExit(listenerLock);
299 }
300 }
301
302 static void JNICALL
acceptThread(jvmtiEnv * jvmti_env,JNIEnv * jni_env,void * arg)303 acceptThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
304 {
305 TransportInfo *info;
306 jdwpTransportEnv *t;
307 jdwpTransportError rc;
308
309 LOG_MISC(("Begin accept thread"));
310
311 info = (TransportInfo*)(void*)arg;
312 t = info->transport;
313
314 rc = (*t)->Accept(t, info->timeout, 0);
315
316 /* System property no longer needed */
317 setTransportProperty(jni_env, NULL);
318
319 if (rc != JDWPTRANSPORT_ERROR_NONE) {
320 /*
321 * If accept fails it probably means a timeout, or another fatal error
322 * We thus exit the VM after stopping the listener.
323 */
324 printLastError(t, rc);
325 (*t)->StopListening(t);
326 EXIT_ERROR(JVMTI_ERROR_NONE, "could not connect, timeout or fatal error");
327 } else {
328 (*t)->StopListening(t);
329 connectionInitiated(t);
330 }
331
332 LOG_MISC(("End accept thread"));
333 }
334
335 static void JNICALL
attachThread(jvmtiEnv * jvmti_env,JNIEnv * jni_env,void * arg)336 attachThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
337 {
338 LOG_MISC(("Begin attach thread"));
339 connectionInitiated((jdwpTransportEnv *)(void*)arg);
340 LOG_MISC(("End attach thread"));
341 }
342
343 void
transport_initialize(void)344 transport_initialize(void)
345 {
346 transport = NULL;
347 listenerLock = debugMonitorCreate("JDWP Transport Listener Monitor");
348 sendLock = debugMonitorCreate("JDWP Transport Send Monitor");
349 }
350
351 void
transport_reset(void)352 transport_reset(void)
353 {
354 /*
355 * Reset the transport by closing any listener (will silently fail
356 * with JDWPTRANSPORT_ERROR_ILLEGAL_STATE if not listening), and
357 * closing any connection (will also fail silently if not
358 * connected).
359 *
360 * Note: There's an assumption here that we don't yet support
361 * multiple transports. When we do then we need a clear transition
362 * from the current transport to the new transport.
363 */
364 if (transport != NULL) {
365 setTransportProperty(getEnv(), NULL);
366 (*transport)->StopListening(transport);
367 (*transport)->Close(transport);
368 }
369 }
370
371 static jdwpError
launch(char * command,char * name,char * address)372 launch(char *command, char *name, char *address)
373 {
374 jint rc;
375 char *buf;
376 char *commandLine;
377 int len;
378
379 /* Construct complete command line (all in UTF-8) */
380 commandLine = jvmtiAllocate((int)strlen(command) +
381 (int)strlen(name) +
382 (int)strlen(address) + 3);
383 if (commandLine == NULL) {
384 return JDWP_ERROR(OUT_OF_MEMORY);
385 }
386 (void)strcpy(commandLine, command);
387 (void)strcat(commandLine, " ");
388 (void)strcat(commandLine, name);
389 (void)strcat(commandLine, " ");
390 (void)strcat(commandLine, address);
391
392 /* Convert commandLine from UTF-8 to platform encoding */
393 len = (int)strlen(commandLine);
394 buf = jvmtiAllocate(len*3+3);
395 (void)(gdata->npt->utf8ToPlatform)(gdata->npt->utf,
396 (jbyte*)commandLine, len, buf, len*3+3);
397
398 /* Exec commandLine */
399 rc = dbgsysExec(buf);
400
401 /* Free up buffers */
402 jvmtiDeallocate(buf);
403 jvmtiDeallocate(commandLine);
404
405 /* And non-zero exit status means we had an error */
406 if (rc != SYS_OK) {
407 return JDWP_ERROR(TRANSPORT_INIT);
408 }
409 return JDWP_ERROR(NONE);
410 }
411
412 jdwpError
transport_startTransport(jboolean isServer,char * name,char * address,long timeout)413 transport_startTransport(jboolean isServer, char *name, char *address,
414 long timeout)
415 {
416 jvmtiStartFunction func;
417 jdwpTransportEnv *trans;
418 char threadName[MAXPATHLEN + 100];
419 jint err;
420 jdwpError serror;
421
422 /*
423 * If the transport is already loaded then use it
424 * Note: We're assuming here that we don't support multiple
425 * transports - when we do then we need to handle the case
426 * where the transport library only supports a single environment.
427 * That probably means we have a bag a transport environments
428 * to correspond to the transports bag.
429 */
430 if (transport != NULL) {
431 trans = transport;
432 } else {
433 serror = loadTransport(name, &trans);
434 if (serror != JDWP_ERROR(NONE)) {
435 return serror;
436 }
437 }
438
439 if (isServer) {
440
441 char *retAddress;
442 char *launchCommand;
443 TransportInfo *info;
444 jvmtiError error;
445 int len;
446 char* prop_value;
447
448 info = jvmtiAllocate(sizeof(*info));
449 if (info == NULL) {
450 return JDWP_ERROR(OUT_OF_MEMORY);
451 }
452 info->name = jvmtiAllocate((int)strlen(name)+1);
453 (void)strcpy(info->name, name);
454 info->address = NULL;
455 info->timeout = timeout;
456 if (info->name == NULL) {
457 serror = JDWP_ERROR(OUT_OF_MEMORY);
458 goto handleError;
459 }
460 if (address != NULL) {
461 info->address = jvmtiAllocate((int)strlen(address)+1);
462 (void)strcpy(info->address, address);
463 if (info->address == NULL) {
464 serror = JDWP_ERROR(OUT_OF_MEMORY);
465 goto handleError;
466 }
467 }
468
469 info->transport = trans;
470
471 err = (*trans)->StartListening(trans, address, &retAddress);
472 if (err != JDWPTRANSPORT_ERROR_NONE) {
473 printLastError(trans, err);
474 serror = JDWP_ERROR(TRANSPORT_INIT);
475 goto handleError;
476 }
477
478 /*
479 * Record listener address in a system property
480 */
481 len = (int)strlen(name) + (int)strlen(retAddress) + 2; /* ':' and '\0' */
482 prop_value = (char*)jvmtiAllocate(len);
483 strcpy(prop_value, name);
484 strcat(prop_value, ":");
485 strcat(prop_value, retAddress);
486 setTransportProperty(getEnv(), prop_value);
487 jvmtiDeallocate(prop_value);
488
489
490 (void)strcpy(threadName, "JDWP Transport Listener: ");
491 (void)strcat(threadName, name);
492
493 func = &acceptThread;
494 error = spawnNewThread(func, (void*)info, threadName);
495 if (error != JVMTI_ERROR_NONE) {
496 serror = map2jdwpError(error);
497 goto handleError;
498 }
499
500 launchCommand = debugInit_launchOnInit();
501 if (launchCommand != NULL) {
502 serror = launch(launchCommand, name, retAddress);
503 if (serror != JDWP_ERROR(NONE)) {
504 goto handleError;
505 }
506 } else {
507 if ( ! gdata->quiet ) {
508 TTY_MESSAGE(("Listening for transport %s at address: %s",
509 name, retAddress));
510 }
511 }
512 return JDWP_ERROR(NONE);
513
514 handleError:
515 jvmtiDeallocate(info->name);
516 jvmtiDeallocate(info->address);
517 jvmtiDeallocate(info);
518 } else {
519 /*
520 * Note that we don't attempt to do a launch here. Launching
521 * is currently supported only in server mode.
522 */
523
524 /*
525 * If we're connecting to another process, there shouldn't be
526 * any concurrent listens, so its ok if we block here in this
527 * thread, waiting for the attach to finish.
528 */
529 err = (*trans)->Attach(trans, address, timeout, 0);
530 if (err != JDWPTRANSPORT_ERROR_NONE) {
531 printLastError(trans, err);
532 serror = JDWP_ERROR(TRANSPORT_INIT);
533 return serror;
534 }
535
536 /*
537 * Start the transport loop in a separate thread
538 */
539 (void)strcpy(threadName, "JDWP Transport Listener: ");
540 (void)strcat(threadName, name);
541
542 func = &attachThread;
543 err = spawnNewThread(func, (void*)trans, threadName);
544 serror = map2jdwpError(err);
545 }
546 return serror;
547 }
548
549 void
transport_close(void)550 transport_close(void)
551 {
552 if ( transport != NULL ) {
553 (*transport)->Close(transport);
554 }
555 }
556
557 jboolean
transport_is_open(void)558 transport_is_open(void)
559 {
560 jboolean is_open = JNI_FALSE;
561
562 if ( transport != NULL ) {
563 is_open = (*transport)->IsOpen(transport);
564 }
565 return is_open;
566 }
567
568 jint
transport_sendPacket(jdwpPacket * packet)569 transport_sendPacket(jdwpPacket *packet)
570 {
571 jdwpTransportError err = JDWPTRANSPORT_ERROR_NONE;
572 jint rc = 0;
573
574 if (transport != NULL) {
575 if ( (*transport)->IsOpen(transport) ) {
576 debugMonitorEnter(sendLock);
577 err = (*transport)->WritePacket(transport, packet);
578 debugMonitorExit(sendLock);
579 }
580 if (err != JDWPTRANSPORT_ERROR_NONE) {
581 if ((*transport)->IsOpen(transport)) {
582 printLastError(transport, err);
583 }
584
585 /*
586 * The users of transport_sendPacket except 0 for
587 * success; non-0 otherwise.
588 */
589 rc = (jint)-1;
590 }
591
592 } /* else, bit bucket */
593
594 return rc;
595 }
596
597 jint
transport_receivePacket(jdwpPacket * packet)598 transport_receivePacket(jdwpPacket *packet)
599 {
600 jdwpTransportError err;
601
602 err = (*transport)->ReadPacket(transport, packet);
603 if (err != JDWPTRANSPORT_ERROR_NONE) {
604 /*
605 * If transport has been closed return EOF
606 */
607 if (!(*transport)->IsOpen(transport)) {
608 packet->type.cmd.len = 0;
609 return 0;
610 }
611
612 printLastError(transport, err);
613
614 /*
615 * Users of transport_receivePacket expect 0 for success,
616 * non-0 otherwise.
617 */
618 return (jint)-1;
619 }
620 return 0;
621 }
622