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

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: Rebase 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
« no previous file with comments | « util/mach/symbolic_constants_mach.h ('k') | util/mach/symbolic_constants_mach_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"},
133 };
134
135 // Returns the short name for a flavor name, given its full flavor name.
136 std::string ThreadStateFlavorFullToShort(const base::StringPiece& flavor) {
137 // For generic flavors like THREAD_STATE_NONE and THREAD_STATE_FLAVOR_LIST_*.
138 const char kThreadState[] = "THREAD_STATE_";
139 size_t prefix_len = strlen(kThreadState);
140 const char* flavor_data = flavor.data();
141 size_t flavor_len = flavor.size();
142 if (flavor_len >= prefix_len &&
143 strncmp(flavor_data, kThreadState, prefix_len) == 0) {
144 return std::string(flavor_data + prefix_len, flavor_len - prefix_len);
145 }
146
147 // For architecture-specific flavors.
148 #if defined(__i386__) || defined(__x86_64__)
149 const char kArchPrefix[] = "x86_";
150 #elif defined(__ppc__) || defined(__ppc64__)
151 const char kArchPrefix[] = "PPC_";
152 #elif defined(__arm__) || defined(__arm64__)
153 const char kArchPrefix[] = "ARM_"
154 #endif
155 prefix_len = strlen(kArchPrefix);
156 if (flavor_len >= prefix_len &&
157 strncmp(flavor_data, kArchPrefix, prefix_len) == 0) {
158 // Shorten the suffix by removing _STATE. If the suffix contains a
159 // significant designation like 32 or 64, keep it, so that a full name like
160 // x86_THREAD_STATE64 becomes a short name like THREAD64.
161 const struct {
162 const char* orig;
163 const char* repl;
164 } kStateSuffixes[] = {
165 {"_STATE", ""},
166 {"_STATE32", "32"},
167 {"_STATE64", "64"},
168 };
169 for (size_t suffix_index = 0;
170 suffix_index < arraysize(kStateSuffixes);
171 ++suffix_index) {
172 const char* suffix = kStateSuffixes[suffix_index].orig;
173 size_t suffix_len = strlen(suffix);
174 if (flavor_len >= suffix_len &&
175 strncmp(flavor_data + flavor_len - suffix_len, suffix, suffix_len) ==
176 0) {
177 std::string s(flavor_data + prefix_len,
178 flavor_len - prefix_len - suffix_len);
179 return s.append(kStateSuffixes[suffix_index].repl);
180 }
181 }
182 }
183
184 return std::string(flavor_data, flavor_len);
185 }
186
187 } // namespace
188
189 namespace crashpad {
190
191 std::string ExceptionToString(exception_type_t exception,
192 SymbolicConstantToStringOptions options) {
193 const char* exception_name =
194 static_cast<size_t>(exception) < arraysize(kExceptionNames)
195 ? kExceptionNames[exception]
196 : NULL;
197 if (!exception_name) {
198 if (options & kUnknownIsNumeric) {
199 return base::StringPrintf("%d", exception);
200 }
201 return std::string();
202 }
203
204 if (options & kUseShortName) {
205 return std::string(exception_name);
206 }
207 return base::StringPrintf("%s%s", kExcPrefix, exception_name);
208 }
209
210 bool StringToException(const base::StringPiece& string,
211 StringToSymbolicConstantOptions options,
212 exception_type_t* exception) {
213 if ((options & kAllowFullName) || (options & kAllowShortName)) {
214 bool can_match_full =
215 (options & kAllowFullName) &&
216 string.substr(0, strlen(kExcPrefix)).compare(kExcPrefix) == 0;
217 base::StringPiece short_string =
218 can_match_full ? string.substr(strlen(kExcPrefix)) : string;
219 for (exception_type_t index = 0;
220 index < static_cast<exception_type_t>(arraysize(kExceptionNames));
221 ++index) {
222 const char* exception_name = kExceptionNames[index];
223 if (!exception_name) {
224 continue;
225 }
226 if (can_match_full && short_string.compare(exception_name) == 0) {
227 *exception = index;
228 return true;
229 }
230 if ((options & kAllowShortName) && string.compare(exception_name) == 0) {
231 *exception = index;
232 return true;
233 }
234 }
235 }
236
237 if (options & kAllowNumber) {
238 return StringToNumber(string, reinterpret_cast<unsigned int*>(exception));
239 }
240
241 return false;
242 }
243
244 std::string ExceptionMaskToString(exception_mask_t exception_mask,
245 SymbolicConstantToStringOptions options) {
246 exception_mask_t local_exception_mask = exception_mask;
247 std::string mask_string;
248 bool has_forbidden_or = false;
249 for (size_t exception = 0;
250 exception < arraysize(kExceptionNames);
251 ++exception) {
252 const char* exception_name = kExceptionNames[exception];
253 exception_mask_t exception_mask_value = 1 << exception;
254 if (exception_name && (local_exception_mask & exception_mask_value)) {
255 if (!mask_string.empty()) {
256 if (!(options & kUseOr)) {
257 has_forbidden_or = true;
258 break;
259 }
260 mask_string.append("|");
261 }
262 if (!(options & kUseShortName)) {
263 mask_string.append(kExcMaskPrefix);
264 }
265 mask_string.append(exception_name);
266 local_exception_mask &= ~exception_mask_value;
267 }
268 }
269
270 if (has_forbidden_or) {
271 local_exception_mask = exception_mask;
272 mask_string.clear();
273 }
274
275 // Deal with any remainder.
276 if (local_exception_mask) {
277 if (!(options & kUnknownIsNumeric)) {
278 return std::string();
279 }
280 if (!mask_string.empty()) {
281 mask_string.append("|");
282 }
283 mask_string.append(base::StringPrintf("%#x", local_exception_mask));
284 }
285
286 return mask_string;
287 }
288
289 bool StringToExceptionMask(const base::StringPiece& string,
290 StringToSymbolicConstantOptions options,
291 exception_mask_t* exception_mask) {
292 if (options & kAllowOr) {
293 options &= ~kAllowOr;
294 exception_mask_t build_mask = 0;
295 size_t pos = -1;
296 do {
297 ++pos;
298 const char* substring_begin = string.begin() + pos;
299 pos = string.find('|', pos);
300 const char* substring_end = (pos == base::StringPiece::npos)
301 ? string.end()
302 : (string.begin() + pos);
303 base::StringPiece substring = string.substr(
304 substring_begin - string.begin(), substring_end - substring_begin);
305
306 exception_mask_t temp_mask;
307 if (!StringToExceptionMask(substring, options, &temp_mask)) {
308 return false;
309 }
310 build_mask |= temp_mask;
311 } while (pos != base::StringPiece::npos);
312
313 *exception_mask = build_mask;
314 return true;
315 }
316
317 if ((options & kAllowFullName) || (options & kAllowShortName)) {
318 bool can_match_full =
319 (options & kAllowFullName) &&
320 string.substr(0, strlen(kExcMaskPrefix)).compare(kExcMaskPrefix) == 0;
321 base::StringPiece short_string =
322 can_match_full ? string.substr(strlen(kExcMaskPrefix)) : string;
323 for (exception_type_t index = 0;
324 index < static_cast<exception_type_t>(arraysize(kExceptionNames));
325 ++index) {
326 const char* exception_name = kExceptionNames[index];
327 if (!exception_name) {
328 continue;
329 }
330 if (can_match_full && short_string.compare(exception_name) == 0) {
331 *exception_mask = 1 << index;
332 return true;
333 }
334 if ((options & kAllowShortName) && string.compare(exception_name) == 0) {
335 *exception_mask = 1 << index;
336 return true;
337 }
338 }
339
340 // EXC_MASK_ALL is a special case: it is not in kExceptionNames as it exists
341 // only as a mask value.
342 const char kExcMaskAll[] = "ALL";
343 if ((can_match_full && short_string.compare(kExcMaskAll) == 0) ||
344 ((options & kAllowShortName) && string.compare(kExcMaskAll) == 0)) {
345 *exception_mask = ExcMaskAll();
346 return true;
347 }
348 }
349
350 if (options & kAllowNumber) {
351 return StringToNumber(string,
352 reinterpret_cast<unsigned int*>(exception_mask));
353 }
354
355 return false;
356 }
357
358 std::string ExceptionBehaviorToString(exception_behavior_t behavior,
359 SymbolicConstantToStringOptions options) {
360 bool mach_exception_codes = behavior & MACH_EXCEPTION_CODES;
361 exception_behavior_t basic_behavior = behavior & ~MACH_EXCEPTION_CODES;
362
363 const char* behavior_name =
364 static_cast<size_t>(basic_behavior) < arraysize(kBehaviorNames)
365 ? kBehaviorNames[basic_behavior]
366 : NULL;
367 if (!behavior_name) {
368 if (options & kUnknownIsNumeric) {
369 return base::StringPrintf("%#x", behavior);
370 }
371 return std::string();
372 }
373
374 std::string behavior_string;
375 if (options & kUseShortName) {
376 behavior_string.assign(behavior_name);
377 } else {
378 behavior_string.assign(base::StringPrintf(
379 "%s%s", kBehaviorPrefix, behavior_name));
380 }
381
382 if (mach_exception_codes) {
383 behavior_string.append("|");
384 behavior_string.append((options & kUseShortName) ? kMachExceptionCodesShort
385 : kMachExceptionCodesFull);
386 }
387
388 return behavior_string;
389 }
390
391 bool StringToExceptionBehavior(const base::StringPiece& string,
392 StringToSymbolicConstantOptions options,
393 exception_behavior_t* behavior) {
394 base::StringPiece sp = string;
395 exception_behavior_t build_behavior = 0;
396 size_t pos = sp.find('|', 0);
397 if (pos != base::StringPiece::npos) {
398 base::StringPiece left = sp.substr(0, pos);
399 base::StringPiece right = sp.substr(pos + 1, sp.length() - pos - 1);
400 if (options & kAllowFullName) {
401 if (left.compare(kMachExceptionCodesFull) == 0) {
402 build_behavior |= MACH_EXCEPTION_CODES;
403 sp = right;
404 } else if (right.compare(kMachExceptionCodesFull) == 0) {
405 build_behavior |= MACH_EXCEPTION_CODES;
406 sp = left;
407 }
408 }
409 if (!(build_behavior & MACH_EXCEPTION_CODES) &&
410 (options & kAllowShortName)) {
411 if (left.compare(kMachExceptionCodesShort) == 0) {
412 build_behavior |= MACH_EXCEPTION_CODES;
413 sp = right;
414 } else if (right.compare(kMachExceptionCodesShort) == 0) {
415 build_behavior |= MACH_EXCEPTION_CODES;
416 sp = left;
417 }
418 }
419 if (!(build_behavior & MACH_EXCEPTION_CODES)) {
420 return false;
421 }
422 }
423
424 if ((options & kAllowFullName) || (options & kAllowShortName)) {
425 bool can_match_full =
426 (options & kAllowFullName) &&
427 sp.substr(0, strlen(kBehaviorPrefix)).compare(kBehaviorPrefix) == 0;
428 base::StringPiece short_string =
429 can_match_full ? sp.substr(strlen(kBehaviorPrefix)) : sp;
430 for (exception_behavior_t index = 0;
431 index < static_cast<exception_behavior_t>(arraysize(kBehaviorNames));
432 ++index) {
433 const char* behavior_name = kBehaviorNames[index];
434 if (!behavior_name) {
435 continue;
436 }
437 if (can_match_full && short_string.compare(behavior_name) == 0) {
438 build_behavior |= index;
439 *behavior = build_behavior;
440 return true;
441 }
442 if ((options & kAllowShortName) && sp.compare(behavior_name) == 0) {
443 build_behavior |= index;
444 *behavior = build_behavior;
445 return true;
446 }
447 }
448 }
449
450 if (options & kAllowNumber) {
451 exception_behavior_t temp_behavior;
452 if (!StringToNumber(sp, reinterpret_cast<unsigned int*>(&temp_behavior))) {
453 return false;
454 }
455 build_behavior |= temp_behavior;
456 *behavior = build_behavior;
457 return true;
458 }
459
460 return false;
461 }
462
463 std::string ThreadStateFlavorToString(thread_state_flavor_t flavor,
464 SymbolicConstantToStringOptions options) {
465 const char* flavor_name =
466 static_cast<size_t>(flavor) < arraysize(kFlavorNames)
467 ? kFlavorNames[flavor]
468 : NULL;
469
470 if (!flavor_name) {
471 for (size_t generic_flavor_index = 0;
472 generic_flavor_index < arraysize(kGenericFlavorNames);
473 ++generic_flavor_index) {
474 if (flavor == kGenericFlavorNames[generic_flavor_index].flavor) {
475 flavor_name = kGenericFlavorNames[generic_flavor_index].name;
476 break;
477 }
478 }
479 }
480
481 if (!flavor_name) {
482 if (options & kUnknownIsNumeric) {
483 return base::StringPrintf("%d", flavor);
484 }
485 return std::string();
486 }
487
488 if (options & kUseShortName) {
489 return ThreadStateFlavorFullToShort(flavor_name);
490 }
491 return std::string(flavor_name);
492 }
493
494 bool StringToThreadStateFlavor(const base::StringPiece& string,
495 StringToSymbolicConstantOptions options,
496 thread_state_flavor_t* flavor) {
497 if ((options & kAllowFullName) || (options & kAllowShortName)) {
498 for (thread_state_flavor_t index = 0;
499 index < static_cast<thread_state_flavor_t>(arraysize(kFlavorNames));
500 ++index) {
501 const char* flavor_name = kFlavorNames[index];
502 if (!flavor_name) {
503 continue;
504 }
505 if ((options & kAllowFullName) && string.compare(flavor_name) == 0) {
506 *flavor = index;
507 return true;
508 }
509 if (options & kAllowShortName) {
510 std::string short_name = ThreadStateFlavorFullToShort(flavor_name);
511 if (string.compare(short_name) == 0) {
512 *flavor = index;
513 return true;
514 }
515 }
516 }
517
518 for (size_t generic_flavor_index = 0;
519 generic_flavor_index < arraysize(kGenericFlavorNames);
520 ++generic_flavor_index) {
521 const char* flavor_name = kGenericFlavorNames[generic_flavor_index].name;
522 thread_state_flavor_t flavor_number =
523 kGenericFlavorNames[generic_flavor_index].flavor;
524 if ((options & kAllowFullName) && string.compare(flavor_name) == 0) {
525 *flavor = flavor_number;
526 return true;
527 }
528 if (options & kAllowShortName) {
529 std::string short_name = ThreadStateFlavorFullToShort(flavor_name);
530 if (string.compare(short_name) == 0) {
531 *flavor = flavor_number;
532 return true;
533 }
534 }
535 }
536 }
537
538 if (options & kAllowNumber) {
539 return StringToNumber(string, reinterpret_cast<unsigned int*>(flavor));
540 }
541
542 return false;
543 }
544
545 } // namespace crashpad
OLDNEW
« no previous file with comments | « util/mach/symbolic_constants_mach.h ('k') | util/mach/symbolic_constants_mach_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698