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 }