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, 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 }
--- EOF ---