1 /* 2 * Copyright (c) 1998, 2012, 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 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 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 * 100 loadTransportLibrary(char *libdir, char *name) 101 { 102 void *handle; 103 char libname[MAXPATHLEN+2]; 104 char buf[MAXPATHLEN*2+100]; 105 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 134 loadTransport(char *name, jdwpTransportEnv **transportPtr) 135 { 136 JNIEnv *env; 137 jdwpTransport_OnLoad_t onLoad; 138 void *handle; 139 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 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 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 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 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 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 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 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 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 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 550 transport_close(void) 551 { 552 if ( transport != NULL ) { 553 (*transport)->Close(transport); 554 } 555 } 556 557 jboolean 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 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 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 }