lin
2025-08-01 633231e833e21d5b8b1c00cb15aedb62b3b78e8f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
 * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
/*
 * handlers
 *
 * The default event request handler functions
 */
 
#include "util.h"
#include "eventHandler.h"
#include "threadControl.h"
#include "eventHelper.h"
#include "classTrack.h"
 
#include "standardHandlers.h"
 
static void
handleClassPrepare(JNIEnv *env, EventInfo *evinfo,
                   HandlerNode *node,
                   struct bag *eventBag)
{
    jthread thread = evinfo->thread;
 
    /* We try hard to avoid class loads/prepares in debugger
     * threads, but it is still possible for them to happen (most
     * likely for exceptions that are thrown within JNI
     * methods). If such an event occurs, we must report it, but
     * we cannot suspend the debugger thread.
     *
     * 1) We report the thread as NULL because we don't want the
     *    application to get hold of a debugger thread object.
     * 2) We try to do the right thing wrt to suspending
     *    threads without suspending debugger threads. If the
     *    requested suspend policy is NONE, there's no problem. If
     *    the requested policy is ALL, we can just suspend all
     *    application threads without producing any surprising
     *    results by leaving the debugger thread running. However,
     *    if the requested policy is EVENT_THREAD, we are forced
     *    to do something different than requested. The most
     *    useful behavior is to suspend all application threads
     *    (just as if the policy was ALL). This allows the
     *    application to operate on the class before it gets into
     *    circulation and so it is preferable to the other
     *    alternative of suspending no threads.
     */
    if (threadControl_isDebugThread(thread)) {
        evinfo->thread = NULL;
        if (node->suspendPolicy == JDWP_SUSPEND_POLICY(EVENT_THREAD)) {
            node->suspendPolicy = JDWP_SUSPEND_POLICY(ALL);
        }
    }
    eventHelper_recordEvent(evinfo, node->handlerID,
                            node->suspendPolicy, eventBag);
}
 
static void
handleGarbageCollectionFinish(JNIEnv *env, EventInfo *evinfo,
                  HandlerNode *node,
                  struct bag *eventBag)
{
    JDI_ASSERT_MSG(JNI_FALSE, "Should never call handleGarbageCollectionFinish");
}
 
static void
handleFrameEvent(JNIEnv *env, EventInfo *evinfo,
                 HandlerNode *node,
                 struct bag *eventBag)
{
    /*
     * The frame id that comes with this event is very transient.
     * We can't send the frame to the helper thread because it
     * might be useless by the time the helper thread can use it
     * (if suspend policy is NONE). So, get the needed info from
     * the frame and then use a special command to the helper
     * thread.
     */
 
    jmethodID method;
    jlocation location;
    jvmtiError error;
    FrameNumber fnum = 0;
    jvalue returnValue;
 
    error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameLocation)
            (gdata->jvmti, evinfo->thread, fnum, &method, &location);
    if (error != JVMTI_ERROR_NONE) {
        location = -1;
    }
    returnValue = evinfo->u.method_exit.return_value;
 
    eventHelper_recordFrameEvent(node->handlerID,
                                 node->suspendPolicy,
                                 evinfo->ei,
                                 evinfo->thread,
                                 evinfo->clazz,
                                 evinfo->method,
                                 location,
                                 node->needReturnValue,
                                 returnValue,
                                 eventBag);
}
 
static void
genericHandler(JNIEnv *env, EventInfo *evinfo,
               HandlerNode *node,
               struct bag *eventBag)
{
    eventHelper_recordEvent(evinfo, node->handlerID, node->suspendPolicy,
                            eventBag);
}
 
HandlerFunction
standardHandlers_defaultHandler(EventIndex ei)
{
    switch (ei) {
        case EI_BREAKPOINT:
        case EI_EXCEPTION:
        case EI_FIELD_ACCESS:
        case EI_FIELD_MODIFICATION:
        case EI_SINGLE_STEP:
        case EI_THREAD_START:
        case EI_THREAD_END:
        case EI_VM_DEATH:
        case EI_MONITOR_CONTENDED_ENTER:
        case EI_MONITOR_CONTENDED_ENTERED:
        case EI_MONITOR_WAIT:
        case EI_MONITOR_WAITED:
            return &genericHandler;
 
        case EI_CLASS_PREPARE:
            return &handleClassPrepare;
 
        case EI_GC_FINISH:
            return &handleGarbageCollectionFinish;
 
        case EI_METHOD_ENTRY:
        case EI_METHOD_EXIT:
            return &handleFrameEvent;
 
        default:
            /* This NULL will trigger a AGENT_ERROR_INVALID_EVENT_TYPE */
            return NULL;
    }
}
 
void
standardHandlers_onConnect(void)
{
    jboolean installed;
 
    /* always report VMDeath to a connected debugger */
    installed = (eventHandler_createPermanentInternal(
                        EI_VM_DEATH, genericHandler) != NULL);
    if (!installed) {
        EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,"Unable to install VM Death event handler");
    }
}
 
void
standardHandlers_onDisconnect(void)
{
}