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