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