• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1998, 2013, 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
printLastError(jdwpTransportEnv * t,jdwpTransportError err)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
findTransportOnLoad(void * handle)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 *
loadTransportLibrary(const char * libdir,const char * name)100 loadTransportLibrary(const char *libdir, const char *name)
101 {
102     void *handle;
103     char libname[MAXPATHLEN+2];
104     char buf[MAXPATHLEN*2+100];
105     const 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
loadTransport(const char * name,jdwpTransportEnv ** transportPtr)134 loadTransport(const char *name, jdwpTransportEnv **transportPtr)
135 {
136     JNIEnv                 *env;
137     jdwpTransport_OnLoad_t  onLoad;
138     void                   *handle;
139     const 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
connectionInitiated(jdwpTransportEnv * t)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
setTransportProperty(JNIEnv * env,char * value)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
transport_waitForConnection(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
acceptThread(jvmtiEnv * jvmti_env,JNIEnv * jni_env,void * arg)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
attachThread(jvmtiEnv * jvmti_env,JNIEnv * jni_env,void * arg)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
transport_initialize(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
transport_reset(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
launch(char * command,char * name,char * address)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
transport_startTransport(jboolean isServer,char * name,char * address,long timeout)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
transport_close(void)550 transport_close(void)
551 {
552     if ( transport != NULL ) {
553         (*transport)->Close(transport);
554     }
555 }
556 
557 jboolean
transport_is_open(void)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
transport_sendPacket(jdwpPacket * packet)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
transport_receivePacket(jdwpPacket * packet)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 }
622