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