Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: util/mach/symbolic_constants_mach.cc

Issue 563383002: Add SymbolicConstantsMach and its test (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/mach/symbolic_constants_mach.h"
16
17 #include <string.h>
18
19 #include "base/basictypes.h"
20 #include "base/strings/stringprintf.h"
21 #include "util/mach/mach_extensions.h"
22 #include "util/stdlib/string_number_conversion.h"
23
24 namespace {
25
26 const char* kExceptionNames[] = {
27 NULL,
28
29 // sed -Ene 's/^#define[[:space:]]EXC_([[:graph:]]+)[[:space:]]+[[:digit:]]{ 1,2}([[:space:]]|$).*/ "\1",/p'
30 // /usr/include/mach/exception_types.h
31 "BAD_ACCESS",
32 "BAD_INSTRUCTION",
33 "ARITHMETIC",
34 "EMULATION",
35 "SOFTWARE",
36 "BREAKPOINT",
37 "SYSCALL",
38 "MACH_SYSCALL",
39 "RPC_ALERT",
40 "CRASH",
41 "RESOURCE",
42 "GUARD",
43 };
44 COMPILE_ASSERT(arraysize(kExceptionNames) == EXC_TYPES_COUNT,
45 kExceptionNames_length);
46
47 const char kExcPrefix[] = "EXC_";
48 const char kExcMaskPrefix[] = "EXC_MASK_";
49
50 const char* kBehaviorNames[] = {
51 NULL,
52
53 // sed -Ene 's/^# define[[:space:]]EXCEPTION_([[:graph:]]+)[[:space:]]+[[:di git:]]{1,2}([[:space:]]|$).*/ "\1",/p'
54 // /usr/include/mach/exception_types.h
55 "DEFAULT",
56 "STATE",
57 "STATE_IDENTITY",
58 };
59
60 const char kBehaviorPrefix[] = "EXCEPTION_";
61 const char kMachExceptionCodesFull[] = "MACH_EXCEPTION_CODES";
62 const char kMachExceptionCodesShort[] = "MACH";
63
64 const char* kFlavorNames[] = {
65 "THREAD_STATE_FLAVOR_LIST",
66
67 #if defined(__i386__) || defined(__x86_64__)
68 // sed -Ene 's/^#define ((x86|THREAD)_[[:graph:]]+)[[:space:]]+[[:digit:]]{1 ,2}.*$/ "\1",/p'
69 // /usr/include/mach/i386/thread_status.h
70 // and then fix up by adding x86_SAVED_STATE32 and x86_SAVED_STATE64.
71 "x86_THREAD_STATE32",
72 "x86_FLOAT_STATE32",
73 "x86_EXCEPTION_STATE32",
74 "x86_THREAD_STATE64",
75 "x86_FLOAT_STATE64",
76 "x86_EXCEPTION_STATE64",
77 "x86_THREAD_STATE",
78 "x86_FLOAT_STATE",
79 "x86_EXCEPTION_STATE",
80 "x86_DEBUG_STATE32",
81 "x86_DEBUG_STATE64",
82 "x86_DEBUG_STATE",
83 "THREAD_STATE_NONE",
84 "x86_SAVED_STATE32",
85 "x86_SAVED_STATE64",
86 "x86_AVX_STATE32",
87 "x86_AVX_STATE64",
88 "x86_AVX_STATE",
89 #elif defined(__ppc__) || defined(__ppc64__)
90 // sed -Ene 's/^#define ((PPC|THREAD)_[[:graph:]]+)[[:space:]]+[[:digit:]]{1 ,2}.*$/ "\1",/p'
91 // usr/include/mach/ppc/thread_status.h
92 // (Mac OS X 10.6 SDK)
93 "PPC_THREAD_STATE",
94 "PPC_FLOAT_STATE",
95 "PPC_EXCEPTION_STATE",
96 "PPC_VECTOR_STATE",
97 "PPC_THREAD_STATE64",
98 "PPC_EXCEPTION_STATE64",
99 "THREAD_STATE_NONE",
100 #elif defined(__arm__) || defined(__arm64__)
101 // sed -Ene 's/^#define ((ARM|THREAD)_[[:graph:]]+)[[:space:]]+[[:digit:]]{1 ,2}.*$/ "\1",/p'
102 // usr/include/mach/arm/thread_status.h
103 // (iOS 7 SDK)
104 // and then fix up by making the list sparse as appropriate.
105 "ARM_THREAD_STATE",
106 "ARM_VFP_STATE",
107 "ARM_EXCEPTION_STATE",
108 "ARM_DEBUG_STATE",
109 "THREAD_STATE_NONE",
110 "ARM_THREAD_STATE64",
111 "ARM_EXCEPTION_STATE64",
112 NULL,
113 "ARM_THREAD_STATE32",
114 NULL,
115 NULL,
116 NULL,
117 NULL,
118 "ARM_DEBUG_STATE32",
119 "ARM_DEBUG_STATE64",
120 "ARM_NEON_STATE",
121 "ARM_NEON_STATE64",
122 #endif
123 };
124
125 // Certain generic flavors have high constants not contiguous with the flavors
126 // above. List them separately alongside their constants.
127 const struct {
128 thread_state_flavor_t flavor;
129 const char* name;
130 } kGenericFlavorNames[] = {
131 {THREAD_STATE_FLAVOR_LIST_NEW, "THREAD_STATE_FLAVOR_LIST_NEW"},
132 {THREAD_STATE_FLAVOR_LIST_10_9, "THREAD_STATE_FLAVOR_LIST_10_9"},
Robert Sesek 2014/09/15 23:00:16 Wtf is this. Good job, Apple… polluting the kernel
Mark Mentovai 2014/09/16 13:42:16 rsesek wrote:
133 };
134
135 std::string ThreadStateFlavorFullToShort(const base::StringPiece& flavor) {
Robert Sesek 2014/09/15 23:00:16 This function warrants a comment.
136 const char kThreadState[] = "THREAD_STATE_";
137 size_t prefix_len = strlen(kThreadState);
138 const char* flavor_data = flavor.data();
139 size_t flavor_len = flavor.size();
140 if (flavor_len >= prefix_len &&
141 strncmp(flavor_data, kThreadState, prefix_len) == 0) {
142 return std::string(flavor_data + prefix_len, flavor_len - prefix_len);
143 }
144
145 #if defined(__i386__) || defined(__x86_64__)
146 const char kArchPrefix[] = "x86_";
147 #elif defined(__ppc__) || defined(__ppc64__)
148 const char kArchPrefix[] = "PPC_";
149 #elif defined(__arm__) || defined(__arm64__)
150 const char kArchPrefix[] = "ARM_"
151 #endif
152 prefix_len = strlen(kArchPrefix);
153 if (flavor_len >= prefix_len &&
154 strncmp(flavor_data, kArchPrefix, prefix_len) == 0) {
155 const struct {
156 const char* orig;
157 const char* repl;
158 } kStateSuffixes[] = {
159 {"_STATE", ""},
160 {"_STATE32", "32"},
161 {"_STATE64", "64"},
162 };
163 for (size_t suffix_index = 0;
164 suffix_index < arraysize(kStateSuffixes);
165 ++suffix_index) {
166 const char* suffix = kStateSuffixes[suffix_index].orig;
167 size_t suffix_len = strlen(suffix);
168 if (flavor_len >= suffix_len &&
169 strncmp(flavor_data + flavor_len - suffix_len, suffix, suffix_len) ==
170 0) {
171 std::string s(flavor_data + prefix_len,
172 flavor_len - prefix_len - suffix_len);
173 return s.append(kStateSuffixes[suffix_index].repl);
174 }
175 }
176 }
177
178 return std::string(flavor_data, flavor_len);
179 }
180
181 } // namespace
182
183 namespace crashpad {
184
185 std::string ExceptionToString(exception_type_t exception,
186 SymbolicConstantToStringOptions options) {
187 const char* exception_name =
188 static_cast<size_t>(exception) < arraysize(kExceptionNames)
189 ? kExceptionNames[exception]
190 : NULL;
191 if (!exception_name) {
192 if (options & kUnknownIsNumeric) {
193 return base::StringPrintf("%d", exception);
194 }
195 return std::string();
196 }
197
198 if (options & kUseShortName) {
199 return std::string(exception_name);
200 }
201 return base::StringPrintf("%s%s", kExcPrefix, exception_name);
202 }
203
204 bool StringToException(const base::StringPiece& string,
205 StringToSymbolicConstantOptions options,
206 exception_type_t* exception) {
207 if ((options & kAllowFullName) || (options & kAllowShortName)) {
208 bool can_match_full =
209 (options & kAllowFullName) &&
210 string.substr(0, strlen(kExcPrefix)).compare(kExcPrefix) == 0;
211 base::StringPiece short_string =
212 can_match_full ? string.substr(strlen(kExcPrefix)) : string;
213 for (exception_type_t index = 0;
214 index < static_cast<exception_type_t>(arraysize(kExceptionNames));
215 ++index) {
216 const char* exception_name = kExceptionNames[index];
217 if (!exception_name) {
218 continue;
219 }
220 if (can_match_full && short_string.compare(exception_name) == 0) {
221 *exception = index;
222 return true;
223 }
224 if ((options & kAllowShortName) && string.compare(exception_name) == 0) {
225 *exception = index;
226 return true;
227 }
228 }
229 }
230
231 if (options & kAllowNumber) {
232 return StringToNumber(string, reinterpret_cast<unsigned int*>(exception));
233 }
234
235 return false;
236 }
237
238 std::string ExceptionMaskToString(exception_mask_t exception_mask,
239 SymbolicConstantToStringOptions options) {
240 exception_mask_t local_exception_mask = exception_mask;
241 std::string mask_string;
242 bool has_forbidden_or = false;
243 for (size_t exception = 0;
244 exception < arraysize(kExceptionNames);
245 ++exception) {
246 const char* exception_name = kExceptionNames[exception];
247 exception_mask_t exception_mask_value = 1 << exception;
248 if (exception_name && (local_exception_mask & exception_mask_value)) {
249 if (!mask_string.empty()) {
250 if (!(options & kUseOr)) {
251 has_forbidden_or = true;
252 break;
253 }
254 mask_string.append("|");
255 }
256 if (!(options & kUseShortName)) {
257 mask_string.append(kExcMaskPrefix);
258 }
259 mask_string.append(exception_name);
260 local_exception_mask &= ~exception_mask_value;
261 }
262 }
263
264 if (has_forbidden_or) {
265 local_exception_mask = exception_mask;
266 mask_string.clear();
267 }
268
269 // Deal with any remainder.
270 if (local_exception_mask) {
271 if (!(options & kUnknownIsNumeric)) {
272 return std::string();
273 }
274 if (!mask_string.empty()) {
275 mask_string.append("|");
276 }
277 mask_string.append(base::StringPrintf("%#x", local_exception_mask));
278 }
279
280 return mask_string;
281 }
282
283 bool StringToExceptionMask(const base::StringPiece& string,
284 StringToSymbolicConstantOptions options,
285 exception_mask_t* exception_mask) {
286 if (options & kAllowOr) {
287 options &= ~kAllowOr;
288 exception_mask_t build_mask = 0;
289 size_t pos = -1;
290 do {
291 ++pos;
292 const char* substring_begin = string.begin() + pos;
293 pos = string.find('|', pos);
294 const char* substring_end = (pos == base::StringPiece::npos)
295 ? string.end()
296 : (string.begin() + pos);
297 base::StringPiece substring = string.substr(
298 substring_begin - string.begin(), substring_end - substring_begin);
299
300 exception_mask_t temp_mask;
301 if (!StringToExceptionMask(substring, options, &temp_mask)) {
302 return false;
303 }
304 build_mask |= temp_mask;
305 } while (pos != base::StringPiece::npos);
306
307 *exception_mask = build_mask;
308 return true;
309 }
310
311 if ((options & kAllowFullName) || (options & kAllowShortName)) {
312 bool can_match_full =
313 (options & kAllowFullName) &&
314 string.substr(0, strlen(kExcMaskPrefix)).compare(kExcMaskPrefix) == 0;
315 base::StringPiece short_string =
316 can_match_full ? string.substr(strlen(kExcMaskPrefix)) : string;
317 for (exception_type_t index = 0;
Robert Sesek 2014/09/15 23:00:16 I do wonder if you could write a (templatized?) fu
Mark Mentovai 2014/09/16 13:42:16 rsesek wrote:
318 index < static_cast<exception_type_t>(arraysize(kExceptionNames));
319 ++index) {
320 const char* exception_name = kExceptionNames[index];
321 if (!exception_name) {
322 continue;
323 }
324 if (can_match_full && short_string.compare(exception_name) == 0) {
325 *exception_mask = 1 << index;
326 return true;
327 }
328 if ((options & kAllowShortName) && string.compare(exception_name) == 0) {
329 *exception_mask = 1 << index;
330 return true;
331 }
332 }
333
334 // EXC_MASK_ALL is a special case: it is not in kExceptionNames as it exists
335 // only as a mask value.
336 const char kExcMaskAll[] = "ALL";
337 if ((can_match_full && short_string.compare(kExcMaskAll) == 0) ||
338 ((options & kAllowShortName) && string.compare(kExcMaskAll) == 0)) {
339 *exception_mask = ExcMaskAll();
340 return true;
341 }
342 }
343
344 if (options & kAllowNumber) {
345 return StringToNumber(string,
346 reinterpret_cast<unsigned int*>(exception_mask));
347 }
348
349 return false;
350 }
351
352 std::string ExceptionBehaviorToString(exception_behavior_t behavior,
353 SymbolicConstantToStringOptions options) {
354 bool mach_exception_codes = behavior & MACH_EXCEPTION_CODES;
355 exception_behavior_t basic_behavior = behavior & ~MACH_EXCEPTION_CODES;
356
357 const char* behavior_name =
358 static_cast<size_t>(basic_behavior) < arraysize(kBehaviorNames)
359 ? kBehaviorNames[basic_behavior]
360 : NULL;
361 if (!behavior_name) {
362 if (options & kUnknownIsNumeric) {
363 return base::StringPrintf("%#x", behavior);
364 }
365 return std::string();
366 }
367
368 std::string behavior_string;
369 if (options & kUseShortName) {
370 behavior_string.assign(behavior_name);
371 } else {
372 behavior_string.assign(base::StringPrintf(
373 "%s%s", kBehaviorPrefix, behavior_name));
374 }
375
376 if (mach_exception_codes) {
377 behavior_string.append("|");
378 behavior_string.append((options & kUseShortName) ? kMachExceptionCodesShort
379 : kMachExceptionCodesFull);
380 }
381
382 return behavior_string;
383 }
384
385 bool StringToExceptionBehavior(const base::StringPiece& string,
386 StringToSymbolicConstantOptions options,
387 exception_behavior_t* behavior) {
388 base::StringPiece sp = string;
389 exception_behavior_t build_behavior = 0;
390 size_t pos = sp.find('|', 0);
391 if (pos != base::StringPiece::npos) {
392 base::StringPiece left = sp.substr(0, pos);
393 base::StringPiece right = sp.substr(pos + 1, sp.length() - pos - 1);
394 if (options & kAllowFullName) {
395 if (left.compare(kMachExceptionCodesFull) == 0) {
396 build_behavior |= MACH_EXCEPTION_CODES;
397 sp = right;
398 } else if (right.compare(kMachExceptionCodesFull) == 0) {
399 build_behavior |= MACH_EXCEPTION_CODES;
400 sp = left;
401 }
402 }
403 if (!(build_behavior & MACH_EXCEPTION_CODES) &&
404 (options & kAllowShortName)) {
405 if (left.compare(kMachExceptionCodesShort) == 0) {
406 build_behavior |= MACH_EXCEPTION_CODES;
407 sp = right;
408 } else if (right.compare(kMachExceptionCodesShort) == 0) {
409 build_behavior |= MACH_EXCEPTION_CODES;
410 sp = left;
411 }
412 }
413 if (!(build_behavior & MACH_EXCEPTION_CODES)) {
414 return false;
415 }
416 }
417
418 if ((options & kAllowFullName) || (options & kAllowShortName)) {
419 bool can_match_full =
420 (options & kAllowFullName) &&
421 sp.substr(0, strlen(kBehaviorPrefix)).compare(kBehaviorPrefix) == 0;
422 base::StringPiece short_string =
423 can_match_full ? sp.substr(strlen(kBehaviorPrefix)) : sp;
424 for (exception_behavior_t index = 0;
425 index < static_cast<exception_behavior_t>(arraysize(kBehaviorNames));
426 ++index) {
427 const char* behavior_name = kBehaviorNames[index];
428 if (!behavior_name) {
429 continue;
430 }
431 if (can_match_full && short_string.compare(behavior_name) == 0) {
432 build_behavior |= index;
433 *behavior = build_behavior;
434 return true;
435 }
436 if ((options & kAllowShortName) && sp.compare(behavior_name) == 0) {
437 build_behavior |= index;
438 *behavior = build_behavior;
439 return true;
440 }
441 }
442 }
443
444 if (options & kAllowNumber) {
445 exception_behavior_t temp_behavior;
446 if (!StringToNumber(sp, reinterpret_cast<unsigned int*>(&temp_behavior))) {
447 return false;
448 }
449 build_behavior |= temp_behavior;
450 *behavior = build_behavior;
451 return true;
452 }
453
454 return false;
455 }
456
457 std::string ThreadStateFlavorToString(thread_state_flavor_t flavor,
458 SymbolicConstantToStringOptions options) {
459 const char* flavor_name =
460 static_cast<size_t>(flavor) < arraysize(kFlavorNames)
461 ? kFlavorNames[flavor]
462 : NULL;
463
464 if (!flavor_name) {
465 for (size_t generic_flavor_index = 0;
466 generic_flavor_index < arraysize(kGenericFlavorNames);
467 ++generic_flavor_index) {
468 if (flavor == kGenericFlavorNames[generic_flavor_index].flavor) {
469 flavor_name = kGenericFlavorNames[generic_flavor_index].name;
470 break;
471 }
472 }
473 }
474
475 if (!flavor_name) {
476 if (options & kUnknownIsNumeric) {
477 return base::StringPrintf("%d", flavor);
478 }
479 return std::string();
480 }
481
482 if (options & kUseShortName) {
483 return ThreadStateFlavorFullToShort(flavor_name);
484 }
485 return std::string(flavor_name);
486 }
487
488 bool StringToThreadStateFlavor(const base::StringPiece& string,
489 StringToSymbolicConstantOptions options,
490 thread_state_flavor_t* flavor) {
491 if ((options & kAllowFullName) || (options & kAllowShortName)) {
492 for (thread_state_flavor_t index = 0;
493 index < static_cast<thread_state_flavor_t>(arraysize(kFlavorNames));
494 ++index) {
495 const char* flavor_name = kFlavorNames[index];
496 if (!flavor_name) {
497 continue;
498 }
499 if ((options & kAllowFullName) && string.compare(flavor_name) == 0) {
500 *flavor = index;
501 return true;
502 }
503 if (options & kAllowShortName) {
504 std::string short_name = ThreadStateFlavorFullToShort(flavor_name);
505 if (string.compare(short_name) == 0) {
506 *flavor = index;
507 return true;
508 }
509 }
510 }
511
512 for (size_t generic_flavor_index = 0;
513 generic_flavor_index < arraysize(kGenericFlavorNames);
514 ++generic_flavor_index) {
515 const char* flavor_name = kGenericFlavorNames[generic_flavor_index].name;
516 thread_state_flavor_t flavor_number =
517 kGenericFlavorNames[generic_flavor_index].flavor;
518 if ((options & kAllowFullName) && string.compare(flavor_name) == 0) {
519 *flavor = flavor_number;
520 return true;
521 }
522 if (options & kAllowShortName) {
523 std::string short_name = ThreadStateFlavorFullToShort(flavor_name);
524 if (string.compare(short_name) == 0) {
525 *flavor = flavor_number;
526 return true;
527 }
528 }
529 }
530 }
531
532 if (options & kAllowNumber) {
533 return StringToNumber(string, reinterpret_cast<unsigned int*>(flavor));
534 }
535
536 return false;
537 }
538
539 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698