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