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