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