Wed, 27 Aug 2014 09:36:55 +0200
Merge
1 /*
2 * Copyright (c) 2011, 2013, 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 */
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"
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 */
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 }
47 void GenDCmdArgument::to_string(jlong l, char* buf, size_t len) {
48 jio_snprintf(buf, len, INT64_FORMAT, l);
49 }
51 void GenDCmdArgument::to_string(bool b, char* buf, size_t len) {
52 jio_snprintf(buf, len, b ? "true" : "false");
53 }
55 void GenDCmdArgument::to_string(NanoTimeArgument n, char* buf, size_t len) {
56 jio_snprintf(buf, len, INT64_FORMAT, n._nanotime);
57 }
59 void GenDCmdArgument::to_string(MemorySizeArgument m, char* buf, size_t len) {
60 jio_snprintf(buf, len, INT64_FORMAT, m._size);
61 }
63 void GenDCmdArgument::to_string(char* c, char* buf, size_t len) {
64 jio_snprintf(buf, len, "%s", (c != NULL) ? c : "");
65 }
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 }
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;
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 }
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 }
116 template <> void DCmdArgument<jlong>::destroy_value() { }
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;
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 }
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 }
151 template <> void DCmdArgument<bool>::destroy_value() { }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
254 template <> void DCmdArgument<NanoTimeArgument>::destroy_value() { }
256 // WARNING StringArrayArgument can only be used as an option, it cannot be
257 // used as an argument with the DCmdParser
259 template <> void DCmdArgument<StringArrayArgument*>::parse_value(const char* str,
260 size_t len, TRAPS) {
261 _value->add(str,len);
262 }
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 }
272 template <> void DCmdArgument<StringArrayArgument*>::destroy_value() {
273 if (_value != NULL) {
274 delete _value;
275 set_value(NULL);
276 }
277 }
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 "Integer parsing error nanotime value: syntax error");
284 }
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 }
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 }
330 template <> void DCmdArgument<MemorySizeArgument>::destroy_value() { }