1 /* 2 * Copyright (c) 2011, 2019, 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/allocation.inline.hpp" 28 #include "memory/resourceArea.hpp" 29 #include "runtime/thread.hpp" 30 #include "services/diagnosticArgument.hpp" 31 32 StringArrayArgument::StringArrayArgument() { 33 _array = new(ResourceObj::C_HEAP, mtInternal)GrowableArray<char *>(32, true); 34 assert(_array != NULL, "Sanity check"); 35 } 36 37 StringArrayArgument::~StringArrayArgument() { 38 for (int i=0; i<_array->length(); i++) { 39 FREE_C_HEAP_ARRAY(char, _array->at(i)); 40 } 41 delete _array; 42 } 43 44 void StringArrayArgument::add(const char* str, size_t len) { 45 if (str != NULL) { 46 char* ptr = NEW_C_HEAP_ARRAY(char, len+1, mtInternal); 47 strncpy(ptr, str, len); 48 ptr[len] = 0; 49 _array->append(ptr); 50 } 51 } 52 53 void GenDCmdArgument::read_value(const char* str, size_t len, TRAPS) { 54 /* NOTE:Some argument types doesn't require a value, 55 * for instance boolean arguments: "enableFeatureX". is 56 * equivalent to "enableFeatureX=true". In these cases, 57 * str will be null. This is perfectly valid. 58 * All argument types must perform null checks on str. 59 */ 60 61 if (is_set() && !allow_multiple()) { 62 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 63 "Duplicates in diagnostic command arguments\n"); 64 } 65 parse_value(str, len, CHECK); 66 set_is_set(true); 67 } 68 69 void GenDCmdArgument::to_string(jlong l, char* buf, size_t len) const { 70 jio_snprintf(buf, len, INT64_FORMAT, l); 71 } 72 73 void GenDCmdArgument::to_string(bool b, char* buf, size_t len) const { 74 jio_snprintf(buf, len, b ? "true" : "false"); 75 } 76 77 void GenDCmdArgument::to_string(NanoTimeArgument n, char* buf, size_t len) const { 78 jio_snprintf(buf, len, INT64_FORMAT, n._nanotime); 79 } 80 81 void GenDCmdArgument::to_string(MemorySizeArgument m, char* buf, size_t len) const { 82 jio_snprintf(buf, len, INT64_FORMAT, m._size); 83 } 84 85 void GenDCmdArgument::to_string(char* c, char* buf, size_t len) const { 86 jio_snprintf(buf, len, "%s", (c != NULL) ? c : ""); 87 } 88 89 void GenDCmdArgument::to_string(StringArrayArgument* f, char* buf, size_t len) const { 90 int length = f->array()->length(); 91 size_t written = 0; 92 buf[0] = 0; 93 for (int i = 0; i < length; i++) { 94 char* next_str = f->array()->at(i); 95 size_t next_size = strlen(next_str); 96 //Check if there's room left to write next element 97 if (written + next_size > len) { 98 return; 99 } 100 //Actually write element 101 strcat(buf, next_str); 102 written += next_size; 103 //Check if there's room left for the comma 104 if (i < length-1 && len - written > 0) { 105 strcat(buf, ","); 106 } 107 } 108 } 109 110 template <> void DCmdArgument<jlong>::parse_value(const char* str, 111 size_t len, TRAPS) { 112 int scanned = -1; 113 if (str == NULL 114 || sscanf(str, JLONG_FORMAT "%n", &_value, &scanned) != 1 115 || (size_t)scanned != len) 116 { 117 ResourceMark rm; 118 119 char* buf = NEW_RESOURCE_ARRAY(char, len + 1); 120 strncpy(buf, str, len); 121 buf[len] = '\0'; 122 Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(), 123 "Integer parsing error in command argument '%s'. Could not parse: %s.\n", _name, buf); 124 } 125 } 126 127 template <> void DCmdArgument<jlong>::init_value(TRAPS) { 128 if (has_default()) { 129 this->parse_value(_default_string, strlen(_default_string), THREAD); 130 if (HAS_PENDING_EXCEPTION) { 131 fatal("Default string must be parseable"); 132 } 133 } else { 134 set_value(0); 135 } 136 } 137 138 template <> void DCmdArgument<jlong>::destroy_value() { } 139 140 template <> void DCmdArgument<bool>::parse_value(const char* str, 141 size_t len, TRAPS) { 142 // len is the length of the current token starting at str 143 if (len == 0) { 144 set_value(true); 145 } else { 146 if (len == strlen("true") && strncasecmp(str, "true", len) == 0) { 147 set_value(true); 148 } else if (len == strlen("false") && strncasecmp(str, "false", len) == 0) { 149 set_value(false); 150 } else { 151 ResourceMark rm; 152 153 char* buf = NEW_RESOURCE_ARRAY(char, len + 1); 154 strncpy(buf, str, len); 155 buf[len] = '\0'; 156 Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(), 157 "Boolean parsing error in command argument '%s'. Could not parse: %s.\n", _name, buf); 158 } 159 } 160 } 161 162 template <> void DCmdArgument<bool>::init_value(TRAPS) { 163 if (has_default()) { 164 this->parse_value(_default_string, strlen(_default_string), THREAD); 165 if (HAS_PENDING_EXCEPTION) { 166 fatal("Default string must be parsable"); 167 } 168 } else { 169 set_value(false); 170 } 171 } 172 173 template <> void DCmdArgument<bool>::destroy_value() { } 174 175 template <> void DCmdArgument<char*>::parse_value(const char* str, 176 size_t len, TRAPS) { 177 if (str == NULL) { 178 _value = NULL; 179 } else { 180 _value = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal); 181 int n = os::snprintf(_value, len + 1, "%.*s", (int)len, str); 182 assert((size_t)n <= len, "Unexpected number of characters in string"); 183 } 184 } 185 186 template <> void DCmdArgument<char*>::init_value(TRAPS) { 187 if (has_default() && _default_string != NULL) { 188 this->parse_value(_default_string, strlen(_default_string), THREAD); 189 if (HAS_PENDING_EXCEPTION) { 190 fatal("Default string must be parsable"); 191 } 192 } else { 193 set_value(NULL); 194 } 195 } 196 197 template <> void DCmdArgument<char*>::destroy_value() { 198 FREE_C_HEAP_ARRAY(char, _value); 199 set_value(NULL); 200 } 201 202 template <> void DCmdArgument<NanoTimeArgument>::parse_value(const char* str, 203 size_t len, TRAPS) { 204 if (str == NULL) { 205 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 206 "Integer parsing error nanotime value: syntax error, value is null\n"); 207 } 208 209 int argc = sscanf(str, JLONG_FORMAT, &_value._time); 210 if (argc != 1) { 211 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 212 "Integer parsing error nanotime value: syntax error\n"); 213 } 214 size_t idx = 0; 215 while(idx < len && isdigit(str[idx])) { 216 idx++; 217 } 218 if (idx == len) { 219 // only accept missing unit if the value is 0 220 if (_value._time != 0) { 221 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 222 "Integer parsing error nanotime value: unit required\n"); 223 } else { 224 _value._nanotime = 0; 225 strcpy(_value._unit, "ns"); 226 return; 227 } 228 } else if(len - idx > 2) { 229 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 230 "Integer parsing error nanotime value: illegal unit\n"); 231 } else { 232 strncpy(_value._unit, &str[idx], len - idx); 233 /*Write an extra null termination. This is safe because _value._unit 234 * is declared as char[3], and length is checked to be not larger than 235 * two above. Also, this is necessary, since length might be 1, and the 236 * default value already in the string is ns, which is two chars. 237 */ 238 _value._unit[len-idx] = '\0'; 239 } 240 241 if (strcmp(_value._unit, "ns") == 0) { 242 _value._nanotime = _value._time; 243 } else if (strcmp(_value._unit, "us") == 0) { 244 _value._nanotime = _value._time * 1000; 245 } else if (strcmp(_value._unit, "ms") == 0) { 246 _value._nanotime = _value._time * 1000 * 1000; 247 } else if (strcmp(_value._unit, "s") == 0) { 248 _value._nanotime = _value._time * 1000 * 1000 * 1000; 249 } else if (strcmp(_value._unit, "m") == 0) { 250 _value._nanotime = _value._time * 60 * 1000 * 1000 * 1000; 251 } else if (strcmp(_value._unit, "h") == 0) { 252 _value._nanotime = _value._time * 60 * 60 * 1000 * 1000 * 1000; 253 } else if (strcmp(_value._unit, "d") == 0) { 254 _value._nanotime = _value._time * 24 * 60 * 60 * 1000 * 1000 * 1000; 255 } else { 256 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 257 "Integer parsing error nanotime value: illegal unit\n"); 258 } 259 } 260 261 template <> void DCmdArgument<NanoTimeArgument>::init_value(TRAPS) { 262 if (has_default()) { 263 this->parse_value(_default_string, strlen(_default_string), THREAD); 264 if (HAS_PENDING_EXCEPTION) { 265 fatal("Default string must be parsable"); 266 } 267 } else { 268 _value._time = 0; 269 _value._nanotime = 0; 270 strcpy(_value._unit, "ns"); 271 } 272 } 273 274 template <> void DCmdArgument<NanoTimeArgument>::destroy_value() { } 275 276 // WARNING StringArrayArgument can only be used as an option, it cannot be 277 // used as an argument with the DCmdParser 278 279 template <> void DCmdArgument<StringArrayArgument*>::parse_value(const char* str, 280 size_t len, TRAPS) { 281 _value->add(str,len); 282 } 283 284 template <> void DCmdArgument<StringArrayArgument*>::init_value(TRAPS) { 285 _value = new StringArrayArgument(); 286 _allow_multiple = true; 287 if (has_default()) { 288 fatal("StringArrayArgument cannot have default value"); 289 } 290 } 291 292 template <> void DCmdArgument<StringArrayArgument*>::destroy_value() { 293 if (_value != NULL) { 294 delete _value; 295 set_value(NULL); 296 } 297 } 298 299 template <> void DCmdArgument<MemorySizeArgument>::parse_value(const char* str, 300 size_t len, TRAPS) { 301 if (str == NULL) { 302 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 303 "Parsing error memory size value: syntax error, value is null\n"); 304 } 305 if (*str == '-') { 306 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 307 "Parsing error memory size value: negative values not allowed\n"); 308 } 309 int res = sscanf(str, UINT64_FORMAT "%c", &_value._val, &_value._multiplier); 310 if (res == 2) { 311 switch (_value._multiplier) { 312 case 'k': case 'K': 313 _value._size = _value._val * 1024; 314 break; 315 case 'm': case 'M': 316 _value._size = _value._val * 1024 * 1024; 317 break; 318 case 'g': case 'G': 319 _value._size = _value._val * 1024 * 1024 * 1024; 320 break; 321 default: 322 _value._size = _value._val; 323 _value._multiplier = ' '; 324 //default case should be to break with no error, since user 325 //can write size in bytes, or might have a delimiter and next arg 326 break; 327 } 328 } else if (res == 1) { 329 _value._size = _value._val; 330 } else { 331 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 332 "Parsing error memory size value: invalid value\n"); 333 } 334 } 335 336 template <> void DCmdArgument<MemorySizeArgument>::init_value(TRAPS) { 337 if (has_default()) { 338 this->parse_value(_default_string, strlen(_default_string), THREAD); 339 if (HAS_PENDING_EXCEPTION) { 340 fatal("Default string must be parsable"); 341 } 342 } else { 343 _value._size = 0; 344 _value._val = 0; 345 _value._multiplier = ' '; 346 } 347 } 348 349 template <> void DCmdArgument<MemorySizeArgument>::destroy_value() { }