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