OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can be | |
4 * found in the LICENSE file. | |
5 */ | |
6 | |
7 /* | |
8 * ragel_tester.c | |
9 * Implements a ragel decoder that can be used as a NaClEnumeratorDecoder. | |
10 */ | |
11 #ifndef NACL_TRUSTED_BUT_NOT_TCB | |
12 #error("This file is not meant for use in the TCB.") | |
13 #endif | |
14 | |
15 #include "native_client/src/trusted/validator/x86/testing/enuminsts/enuminsts.h" | |
16 | |
17 #include <string.h> | |
18 #include "native_client/src/trusted/validator/types_memory_model.h" | |
19 #include "native_client/src/trusted/validator/x86/ncinstbuffer.h" | |
20 #include "native_client/src/trusted/validator/x86/testing/enuminsts/str_utils.h" | |
21 #include "native_client/src/trusted/validator_ragel/validator.h" | |
22 | |
23 #define kBufferSize 1024 | |
24 | |
25 /* Defines the virtual table for the ragel decoder. */ | |
26 struct { | |
27 /* The virtual table that implements this decoder. */ | |
28 NaClEnumeratorDecoder _base; | |
29 } ragel_decoder; | |
30 | |
31 /* Initialize ragel state before we try to decode anything. */ | |
32 static void RagelSetup(void) { | |
33 } | |
34 | |
35 struct RagelDecodeState { | |
36 const uint8_t *inst_offset; | |
37 uint8_t inst_num_bytes; | |
38 uint8_t first_call; | |
39 const char *inst_name; | |
40 int inst_is_legal; /* legal means decodes correctly */ | |
41 int inst_is_valid; /* valid means validator is happy */ | |
42 }; | |
43 struct RagelDecodeState RState; | |
44 | |
45 static const char* RGetInstMnemonic(const NaClEnumerator* enumerator) { | |
46 UNREFERENCED_PARAMETER(enumerator); | |
47 return RState.inst_name; | |
48 } | |
49 | |
50 static void RagelPrintInst(void) { | |
51 int i; | |
52 int print_num_bytes = RState.inst_num_bytes; | |
53 | |
54 if (print_num_bytes == 0) print_num_bytes = 4; | |
55 for (i = 0; i < print_num_bytes; i++) { | |
56 printf("%02x ", RState.inst_offset[i]); | |
57 } | |
58 printf("\n"); | |
59 } | |
60 | |
61 | |
62 Bool RagelInstruction(const uint8_t *begin, const uint8_t *end, | |
63 uint32_t info, void *userdata) { | |
64 struct RagelDecodeState *rstate = (struct RagelDecodeState *)userdata; | |
65 | |
66 /* Only look at the first instruction. */ | |
67 if (rstate->first_call) { | |
68 int restricted_register = | |
69 (info & RESTRICTED_REGISTER_MASK) >> RESTRICTED_REGISTER_SHIFT; | |
70 rstate->inst_num_bytes = (uint8_t)(end - begin); | |
71 | |
72 rstate->inst_is_valid = | |
73 !(info & (VALIDATION_ERRORS_MASK & ~DIRECT_JUMP_OUT_OF_RANGE)) && | |
74 restricted_register != REG_RSP && | |
75 restricted_register != REG_RBP; | |
76 rstate->inst_is_legal = rstate->inst_is_valid; | |
77 rstate->first_call = 0; | |
78 } | |
79 | |
80 if (info & (VALIDATION_ERRORS_MASK | BAD_JUMP_TARGET)) | |
81 return FALSE; | |
82 else | |
83 return TRUE; | |
84 } | |
85 | |
86 static void InitializeRagelDecodeState(struct RagelDecodeState *rs, | |
87 const uint8_t *itext) { | |
88 rs->first_call = 1; | |
89 rs->inst_offset = itext; | |
90 rs->inst_num_bytes = 0; | |
91 rs->inst_is_legal = 0; | |
92 rs->inst_is_valid = 0; | |
93 rs->inst_name = "undefined"; | |
94 } | |
95 | |
96 /* Defines the function to parse the first instruction. Note RState.ready */ | |
97 /* mechanism forces parsing of at most one instruction. */ | |
98 static void RParseInst(const NaClEnumerator* enumerator, const int pc_address) { | |
99 uint8_t chunk[(NACL_ENUM_MAX_INSTRUCTION_BYTES + kBundleMask) & | |
100 ~kBundleMask]; | |
101 | |
102 UNREFERENCED_PARAMETER(pc_address); | |
103 InitializeRagelDecodeState(&RState, enumerator->_itext); | |
104 | |
105 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_TARGET_SUBARCH == 64 | |
106 #define ValidateChunkArch ValidateChunkAMD64 | |
107 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_TARGET_SUBARCH == 32 | |
108 #define ValidateChunkArch ValidateChunkIA32 | |
109 #else | |
110 #error("Unsupported architecture") | |
111 #endif | |
112 | |
113 /* Copy the command. */ | |
114 memcpy(chunk, enumerator->_itext, sizeof enumerator->_itext); | |
115 /* Fill the rest with HLTs. */ | |
116 memset(chunk + sizeof enumerator->_itext, 0xf4, | |
117 sizeof chunk - sizeof enumerator->_itext); | |
118 ValidateChunkArch(chunk, sizeof(chunk), | |
119 CALL_USER_CALLBACK_ON_EACH_INSTRUCTION, | |
120 &kFullCPUIDFeatures, | |
121 RagelInstruction, &RState); | |
122 | |
123 #undef ValidateChunkArch | |
124 } | |
125 | |
126 /* Returns true if the instruction parsed a legal instruction. */ | |
127 static Bool RIsInstLegal(const NaClEnumerator* enumerator) { | |
128 UNREFERENCED_PARAMETER(enumerator); | |
129 return RState.inst_is_legal; | |
130 } | |
131 | |
132 /* Returns true if the instruction parsed a legal instruction. */ | |
133 static Bool RIsInstValid(const NaClEnumerator* enumerator) { | |
134 UNREFERENCED_PARAMETER(enumerator); | |
135 return RState.inst_is_valid; | |
136 } | |
137 | |
138 /* Prints out the disassembled instruction. */ | |
139 static void RPrintInst(const NaClEnumerator* enumerator) { | |
140 UNREFERENCED_PARAMETER(enumerator); | |
141 printf("Ragel: "); | |
142 RagelPrintInst(); | |
143 } | |
144 | |
145 static size_t RInstLength(const NaClEnumerator* enumerator) { | |
146 UNREFERENCED_PARAMETER(enumerator); | |
147 return (size_t)RState.inst_num_bytes; | |
148 } | |
149 | |
150 static void InstallFlag(const NaClEnumerator* enumerator, | |
151 const char* flag_name, | |
152 const void* flag_address) { | |
153 UNREFERENCED_PARAMETER(enumerator); | |
154 UNREFERENCED_PARAMETER(flag_name); | |
155 UNREFERENCED_PARAMETER(flag_address); | |
156 } | |
157 | |
158 /* Defines the registry function that creates a ragel decoder, and returns | |
159 * the decoder to be registered. | |
160 */ | |
161 NaClEnumeratorDecoder* RegisterRagelDecoder(void) { | |
162 RagelSetup(); | |
163 ragel_decoder._base._id_name = "ragel"; | |
164 ragel_decoder._base._parse_inst_fn = RParseInst; | |
165 ragel_decoder._base._inst_length_fn = RInstLength; | |
166 ragel_decoder._base._print_inst_fn = RPrintInst; | |
167 ragel_decoder._base._is_inst_legal_fn = RIsInstLegal; | |
168 ragel_decoder._base._install_flag_fn = InstallFlag; | |
169 ragel_decoder._base._get_inst_mnemonic_fn = RGetInstMnemonic; | |
170 ragel_decoder._base._get_inst_num_operands_fn = NULL; | |
171 ragel_decoder._base._get_inst_operands_text_fn = NULL; | |
172 ragel_decoder._base._writes_to_reserved_reg_fn = NULL; | |
173 ragel_decoder._base._maybe_inst_validates_fn = RIsInstValid; | |
174 ragel_decoder._base._segment_validates_fn = NULL; | |
175 ragel_decoder._base._usage_message = "Runs ragel to decode instructions."; | |
176 return &ragel_decoder._base; | |
177 } | |
OLD | NEW |