rev 12879 : 8136556: Add the ability to perform static builds of MacOSX x64 binaries
Reviewed-by: ihse, bdelsart, gadams, lfoltan, rriggs, hseigel, twisti

   1 /*
   2  * Copyright (c) 1998, 2014, 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     void *handle;
 105     char libname[MAXPATHLEN+2];
 106     char buf[MAXPATHLEN*2+100];
 107     const char *plibdir;
 108 
 109     /* Convert libdir from UTF-8 to platform encoding */
 110     plibdir = NULL;
 111     if ( libdir != NULL ) {
 112         int  len;
 113 
 114         len = (int)strlen(libdir);
 115         (void)utf8ToPlatform((jbyte*)libdir, len, buf, (int)sizeof(buf));
 116         plibdir = buf;
 117     }
 118 
 119     /* Construct library name (simple name or full path) */
 120     dbgsysBuildLibName(libname, sizeof(libname), plibdir, name);
 121     if (strlen(libname) == 0) {
 122         return NULL;
 123     }
 124 
 125     /* dlopen (unix) / LoadLibrary (windows) the transport library */
 126     handle = dbgsysLoadLibrary(libname, buf, sizeof(buf));
 127     return handle;



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