Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/services/diagnosticFramework.cpp
41144 views
1
/*
2
* Copyright (c) 2011, 2020, 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.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
25
#include "precompiled.hpp"
26
#include "jvm.h"
27
#include "memory/oopFactory.hpp"
28
#include "memory/resourceArea.hpp"
29
#include "oops/oop.inline.hpp"
30
#include "runtime/handles.inline.hpp"
31
#include "runtime/javaCalls.hpp"
32
#include "runtime/mutexLocker.hpp"
33
#include "services/diagnosticArgument.hpp"
34
#include "services/diagnosticFramework.hpp"
35
#include "services/management.hpp"
36
37
CmdLine::CmdLine(const char* line, size_t len, bool no_command_name)
38
: _cmd(line), _cmd_len(0), _args(NULL), _args_len(0)
39
{
40
assert(line != NULL, "Command line string should not be NULL");
41
const char* line_end;
42
const char* cmd_end;
43
44
_cmd = line;
45
line_end = &line[len];
46
47
// Skip whitespace in the beginning of the line.
48
while (_cmd < line_end && isspace((int) _cmd[0])) {
49
_cmd++;
50
}
51
cmd_end = _cmd;
52
53
if (no_command_name) {
54
_cmd = NULL;
55
_cmd_len = 0;
56
} else {
57
// Look for end of the command name
58
while (cmd_end < line_end && !isspace((int) cmd_end[0])) {
59
cmd_end++;
60
}
61
_cmd_len = cmd_end - _cmd;
62
}
63
_args = cmd_end;
64
_args_len = line_end - _args;
65
}
66
67
bool DCmdArgIter::next(TRAPS) {
68
if (_len == 0) return false;
69
// skipping delimiters
70
while (_cursor < _len - 1 && _buffer[_cursor] == _delim) {
71
_cursor++;
72
}
73
// handling end of command line
74
if (_cursor == _len - 1 && _buffer[_cursor] == _delim) {
75
_key_addr = &_buffer[_cursor];
76
_key_len = 0;
77
_value_addr = &_buffer[_cursor];
78
_value_len = 0;
79
return false;
80
}
81
// extracting first item, argument or option name
82
_key_addr = &_buffer[_cursor];
83
bool arg_had_quotes = false;
84
while (_cursor <= _len - 1 && _buffer[_cursor] != '=' && _buffer[_cursor] != _delim) {
85
// argument can be surrounded by single or double quotes
86
if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') {
87
_key_addr++;
88
char quote = _buffer[_cursor];
89
arg_had_quotes = true;
90
while (_cursor < _len - 1) {
91
_cursor++;
92
if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') {
93
break;
94
}
95
}
96
if (_buffer[_cursor] != quote) {
97
THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
98
"Format error in diagnostic command arguments", false);
99
}
100
break;
101
}
102
_cursor++;
103
}
104
_key_len = &_buffer[_cursor] - _key_addr;
105
if (arg_had_quotes) {
106
// if the argument was quoted, we need to step past the last quote here
107
_cursor++;
108
}
109
// check if the argument has the <key>=<value> format
110
if (_cursor <= _len -1 && _buffer[_cursor] == '=') {
111
_cursor++;
112
_value_addr = &_buffer[_cursor];
113
bool value_had_quotes = false;
114
// extract the value
115
while (_cursor <= _len - 1 && _buffer[_cursor] != _delim) {
116
// value can be surrounded by simple or double quotes
117
if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') {
118
_value_addr++;
119
char quote = _buffer[_cursor];
120
value_had_quotes = true;
121
while (_cursor < _len - 1) {
122
_cursor++;
123
if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') {
124
break;
125
}
126
}
127
if (_buffer[_cursor] != quote) {
128
THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
129
"Format error in diagnostic command arguments", false);
130
}
131
break;
132
}
133
_cursor++;
134
}
135
_value_len = &_buffer[_cursor] - _value_addr;
136
if (value_had_quotes) {
137
// if the value was quoted, we need to step past the last quote here
138
_cursor++;
139
}
140
} else {
141
_value_addr = NULL;
142
_value_len = 0;
143
}
144
return _key_len != 0;
145
}
146
147
bool DCmdInfo::by_name(void* cmd_name, DCmdInfo* info) {
148
if (info == NULL) return false;
149
return strcmp((const char*)cmd_name, info->name()) == 0;
150
}
151
152
void DCmdParser::add_dcmd_option(GenDCmdArgument* arg) {
153
assert(arg != NULL, "Sanity");
154
if (_options == NULL) {
155
_options = arg;
156
} else {
157
GenDCmdArgument* o = _options;
158
while (o->next() != NULL) {
159
o = o->next();
160
}
161
o->set_next(arg);
162
}
163
arg->set_next(NULL);
164
JavaThread* THREAD = JavaThread::current(); // For exception macros.
165
arg->init_value(THREAD);
166
if (HAS_PENDING_EXCEPTION) {
167
fatal("Initialization must be successful");
168
}
169
}
170
171
void DCmdParser::add_dcmd_argument(GenDCmdArgument* arg) {
172
assert(arg != NULL, "Sanity");
173
if (_arguments_list == NULL) {
174
_arguments_list = arg;
175
} else {
176
GenDCmdArgument* a = _arguments_list;
177
while (a->next() != NULL) {
178
a = a->next();
179
}
180
a->set_next(arg);
181
}
182
arg->set_next(NULL);
183
JavaThread* THREAD = JavaThread::current(); // For exception macros.
184
arg->init_value(THREAD);
185
if (HAS_PENDING_EXCEPTION) {
186
fatal("Initialization must be successful");
187
}
188
}
189
190
void DCmdParser::parse(CmdLine* line, char delim, TRAPS) {
191
GenDCmdArgument* next_argument = _arguments_list;
192
DCmdArgIter iter(line->args_addr(), line->args_len(), delim);
193
bool cont = iter.next(CHECK);
194
while (cont) {
195
GenDCmdArgument* arg = lookup_dcmd_option(iter.key_addr(),
196
iter.key_length());
197
if (arg != NULL) {
198
arg->read_value(iter.value_addr(), iter.value_length(), CHECK);
199
} else {
200
if (next_argument != NULL) {
201
arg = next_argument;
202
arg->read_value(iter.key_addr(), iter.key_length(), CHECK);
203
next_argument = next_argument->next();
204
} else {
205
const size_t buflen = 120;
206
const size_t argbuflen = 30;
207
char buf[buflen];
208
char argbuf[argbuflen];
209
size_t len = MIN2<size_t>(iter.key_length(), argbuflen - 1);
210
211
strncpy(argbuf, iter.key_addr(), len);
212
argbuf[len] = '\0';
213
jio_snprintf(buf, buflen - 1, "Unknown argument '%s' in diagnostic command.", argbuf);
214
215
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);
216
}
217
}
218
cont = iter.next(CHECK);
219
}
220
check(CHECK);
221
}
222
223
GenDCmdArgument* DCmdParser::lookup_dcmd_option(const char* name, size_t len) {
224
GenDCmdArgument* arg = _options;
225
while (arg != NULL) {
226
if (strlen(arg->name()) == len &&
227
strncmp(name, arg->name(), len) == 0) {
228
return arg;
229
}
230
arg = arg->next();
231
}
232
return NULL;
233
}
234
235
void DCmdParser::check(TRAPS) {
236
const size_t buflen = 256;
237
char buf[buflen];
238
GenDCmdArgument* arg = _arguments_list;
239
while (arg != NULL) {
240
if (arg->is_mandatory() && !arg->has_value()) {
241
jio_snprintf(buf, buflen - 1, "The argument '%s' is mandatory.", arg->name());
242
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);
243
}
244
arg = arg->next();
245
}
246
arg = _options;
247
while (arg != NULL) {
248
if (arg->is_mandatory() && !arg->has_value()) {
249
jio_snprintf(buf, buflen - 1, "The option '%s' is mandatory.", arg->name());
250
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);
251
}
252
arg = arg->next();
253
}
254
}
255
256
void DCmdParser::print_help(outputStream* out, const char* cmd_name) const {
257
out->print("Syntax : %s %s", cmd_name, _options == NULL ? "" : "[options]");
258
GenDCmdArgument* arg = _arguments_list;
259
while (arg != NULL) {
260
if (arg->is_mandatory()) {
261
out->print(" <%s>", arg->name());
262
} else {
263
out->print(" [<%s>]", arg->name());
264
}
265
arg = arg->next();
266
}
267
out->cr();
268
if (_arguments_list != NULL) {
269
out->print_cr("\nArguments:");
270
arg = _arguments_list;
271
while (arg != NULL) {
272
out->print("\t%s : %s %s (%s, ", arg->name(),
273
arg->is_mandatory() ? "" : "[optional]",
274
arg->description(), arg->type());
275
if (arg->has_default()) {
276
out->print("%s", arg->default_string());
277
} else {
278
out->print("no default value");
279
}
280
out->print_cr(")");
281
arg = arg->next();
282
}
283
}
284
if (_options != NULL) {
285
out->print_cr("\nOptions: (options must be specified using the <key> or <key>=<value> syntax)");
286
arg = _options;
287
while (arg != NULL) {
288
out->print("\t%s : %s %s (%s, ", arg->name(),
289
arg->is_mandatory() ? "" : "[optional]",
290
arg->description(), arg->type());
291
if (arg->has_default()) {
292
out->print("%s", arg->default_string());
293
} else {
294
out->print("no default value");
295
}
296
out->print_cr(")");
297
arg = arg->next();
298
}
299
}
300
}
301
302
void DCmdParser::reset(TRAPS) {
303
GenDCmdArgument* arg = _arguments_list;
304
while (arg != NULL) {
305
arg->reset(CHECK);
306
arg = arg->next();
307
}
308
arg = _options;
309
while (arg != NULL) {
310
arg->reset(CHECK);
311
arg = arg->next();
312
}
313
}
314
315
void DCmdParser::cleanup() {
316
GenDCmdArgument* arg = _arguments_list;
317
while (arg != NULL) {
318
arg->cleanup();
319
arg = arg->next();
320
}
321
arg = _options;
322
while (arg != NULL) {
323
arg->cleanup();
324
arg = arg->next();
325
}
326
}
327
328
int DCmdParser::num_arguments() const {
329
GenDCmdArgument* arg = _arguments_list;
330
int count = 0;
331
while (arg != NULL) {
332
count++;
333
arg = arg->next();
334
}
335
arg = _options;
336
while (arg != NULL) {
337
count++;
338
arg = arg->next();
339
}
340
return count;
341
}
342
343
GrowableArray<const char *>* DCmdParser::argument_name_array() const {
344
int count = num_arguments();
345
GrowableArray<const char *>* array = new GrowableArray<const char *>(count);
346
GenDCmdArgument* arg = _arguments_list;
347
while (arg != NULL) {
348
array->append(arg->name());
349
arg = arg->next();
350
}
351
arg = _options;
352
while (arg != NULL) {
353
array->append(arg->name());
354
arg = arg->next();
355
}
356
return array;
357
}
358
359
GrowableArray<DCmdArgumentInfo*>* DCmdParser::argument_info_array() const {
360
int count = num_arguments();
361
GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo *>(count);
362
int idx = 0;
363
GenDCmdArgument* arg = _arguments_list;
364
while (arg != NULL) {
365
array->append(new DCmdArgumentInfo(arg->name(), arg->description(),
366
arg->type(), arg->default_string(), arg->is_mandatory(),
367
false, arg->allow_multiple(), idx));
368
idx++;
369
arg = arg->next();
370
}
371
arg = _options;
372
while (arg != NULL) {
373
array->append(new DCmdArgumentInfo(arg->name(), arg->description(),
374
arg->type(), arg->default_string(), arg->is_mandatory(),
375
true, arg->allow_multiple()));
376
arg = arg->next();
377
}
378
return array;
379
}
380
381
DCmdFactory* DCmdFactory::_DCmdFactoryList = NULL;
382
bool DCmdFactory::_has_pending_jmx_notification = false;
383
384
void DCmd::parse_and_execute(DCmdSource source, outputStream* out,
385
const char* cmdline, char delim, TRAPS) {
386
387
if (cmdline == NULL) return; // Nothing to do!
388
DCmdIter iter(cmdline, '\n');
389
390
int count = 0;
391
while (iter.has_next()) {
392
if(source == DCmd_Source_MBean && count > 0) {
393
// When diagnostic commands are invoked via JMX, each command line
394
// must contains one and only one command because of the Permission
395
// checks performed by the DiagnosticCommandMBean
396
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
397
"Invalid syntax");
398
}
399
CmdLine line = iter.next();
400
if (line.is_stop()) {
401
break;
402
}
403
if (line.is_executable()) {
404
ResourceMark rm;
405
DCmd* command = DCmdFactory::create_local_DCmd(source, line, out, CHECK);
406
assert(command != NULL, "command error must be handled before this line");
407
DCmdMark mark(command);
408
command->parse(&line, delim, CHECK);
409
command->execute(source, CHECK);
410
}
411
count++;
412
}
413
}
414
415
void DCmdWithParser::parse(CmdLine* line, char delim, TRAPS) {
416
_dcmdparser.parse(line, delim, CHECK);
417
}
418
419
void DCmdWithParser::print_help(const char* name) const {
420
_dcmdparser.print_help(output(), name);
421
}
422
423
void DCmdWithParser::reset(TRAPS) {
424
_dcmdparser.reset(CHECK);
425
}
426
427
void DCmdWithParser::cleanup() {
428
_dcmdparser.cleanup();
429
}
430
431
GrowableArray<const char*>* DCmdWithParser::argument_name_array() const {
432
return _dcmdparser.argument_name_array();
433
}
434
435
GrowableArray<DCmdArgumentInfo*>* DCmdWithParser::argument_info_array() const {
436
return _dcmdparser.argument_info_array();
437
}
438
439
void DCmdFactory::push_jmx_notification_request() {
440
MutexLocker ml(Notification_lock, Mutex::_no_safepoint_check_flag);
441
_has_pending_jmx_notification = true;
442
Notification_lock->notify_all();
443
}
444
445
void DCmdFactory::send_notification(TRAPS) {
446
DCmdFactory::send_notification_internal(THREAD);
447
// Clearing pending exception to avoid premature termination of
448
// the service thread
449
if (HAS_PENDING_EXCEPTION) {
450
CLEAR_PENDING_EXCEPTION;
451
}
452
}
453
void DCmdFactory::send_notification_internal(TRAPS) {
454
ResourceMark rm(THREAD);
455
HandleMark hm(THREAD);
456
bool notif = false;
457
{
458
MutexLocker ml(THREAD, Notification_lock, Mutex::_no_safepoint_check_flag);
459
notif = _has_pending_jmx_notification;
460
_has_pending_jmx_notification = false;
461
}
462
if (notif) {
463
464
Klass* k = Management::com_sun_management_internal_DiagnosticCommandImpl_klass(CHECK);
465
InstanceKlass* dcmd_mbean_klass = InstanceKlass::cast(k);
466
467
JavaValue result(T_OBJECT);
468
JavaCalls::call_static(&result,
469
dcmd_mbean_klass,
470
vmSymbols::getDiagnosticCommandMBean_name(),
471
vmSymbols::getDiagnosticCommandMBean_signature(),
472
CHECK);
473
474
instanceOop m = (instanceOop) result.get_oop();
475
instanceHandle dcmd_mbean_h(THREAD, m);
476
477
if (!dcmd_mbean_h->is_a(k)) {
478
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
479
"DiagnosticCommandImpl.getDiagnosticCommandMBean didn't return a DiagnosticCommandMBean instance");
480
}
481
482
JavaValue result2(T_VOID);
483
JavaCallArguments args2(dcmd_mbean_h);
484
485
JavaCalls::call_virtual(&result2,
486
dcmd_mbean_klass,
487
vmSymbols::createDiagnosticFrameworkNotification_name(),
488
vmSymbols::void_method_signature(),
489
&args2,
490
CHECK);
491
}
492
}
493
494
bool DCmdFactory::_send_jmx_notification = false;
495
496
DCmdFactory* DCmdFactory::factory(DCmdSource source, const char* name, size_t len) {
497
MutexLocker ml(DCmdFactory_lock, Mutex::_no_safepoint_check_flag);
498
DCmdFactory* factory = _DCmdFactoryList;
499
while (factory != NULL) {
500
if (strlen(factory->name()) == len &&
501
strncmp(name, factory->name(), len) == 0) {
502
if(factory->export_flags() & source) {
503
return factory;
504
} else {
505
return NULL;
506
}
507
}
508
factory = factory->_next;
509
}
510
return NULL;
511
}
512
513
int DCmdFactory::register_DCmdFactory(DCmdFactory* factory) {
514
MutexLocker ml(DCmdFactory_lock, Mutex::_no_safepoint_check_flag);
515
factory->_next = _DCmdFactoryList;
516
_DCmdFactoryList = factory;
517
if (_send_jmx_notification && !factory->_hidden
518
&& (factory->_export_flags & DCmd_Source_MBean)) {
519
DCmdFactory::push_jmx_notification_request();
520
}
521
return 0; // Actually, there's no checks for duplicates
522
}
523
524
DCmd* DCmdFactory::create_local_DCmd(DCmdSource source, CmdLine &line,
525
outputStream* out, TRAPS) {
526
DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len());
527
if (f != NULL) {
528
if (!f->is_enabled()) {
529
THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
530
f->disabled_message());
531
}
532
return f->create_resource_instance(out);
533
}
534
THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
535
"Unknown diagnostic command");
536
}
537
538
GrowableArray<const char*>* DCmdFactory::DCmd_list(DCmdSource source) {
539
MutexLocker ml(DCmdFactory_lock, Mutex::_no_safepoint_check_flag);
540
GrowableArray<const char*>* array = new GrowableArray<const char*>();
541
DCmdFactory* factory = _DCmdFactoryList;
542
while (factory != NULL) {
543
if (!factory->is_hidden() && (factory->export_flags() & source)) {
544
array->append(factory->name());
545
}
546
factory = factory->next();
547
}
548
return array;
549
}
550
551
GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list(DCmdSource source ) {
552
MutexLocker ml(DCmdFactory_lock, Mutex::_no_safepoint_check_flag);
553
GrowableArray<DCmdInfo*>* array = new GrowableArray<DCmdInfo*>();
554
DCmdFactory* factory = _DCmdFactoryList;
555
while (factory != NULL) {
556
if (!factory->is_hidden() && (factory->export_flags() & source)) {
557
array->append(new DCmdInfo(factory->name(),
558
factory->description(), factory->impact(),
559
factory->permission(), factory->num_arguments(),
560
factory->is_enabled()));
561
}
562
factory = factory->next();
563
}
564
return array;
565
}
566
567