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