/src/zydis/include/Zydis/Internal/FormatterBase.h
Line | Count | Source (jump to first uncovered line) |
1 | | /*************************************************************************************************** |
2 | | |
3 | | Zyan Disassembler Library (Zydis) |
4 | | |
5 | | Original Author : Florian Bernd, Joel Hoener |
6 | | |
7 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | | * of this software and associated documentation files (the "Software"), to deal |
9 | | * in the Software without restriction, including without limitation the rights |
10 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 | | * copies of the Software, and to permit persons to whom the Software is |
12 | | * furnished to do so, subject to the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be included in all |
15 | | * copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | | * SOFTWARE. |
24 | | |
25 | | ***************************************************************************************************/ |
26 | | |
27 | | /** |
28 | | * @file |
29 | | * Provides formatter functions that are shared between the different formatters. |
30 | | */ |
31 | | |
32 | | #ifndef ZYDIS_FORMATTER_BASE_H |
33 | | #define ZYDIS_FORMATTER_BASE_H |
34 | | |
35 | | #include <Zydis/Formatter.h> |
36 | | #include <Zydis/Internal/String.h> |
37 | | |
38 | | #ifdef __cplusplus |
39 | | extern "C" { |
40 | | #endif |
41 | | |
42 | | /* ============================================================================================== */ |
43 | | /* Macros */ |
44 | | /* ============================================================================================== */ |
45 | | |
46 | | /* ---------------------------------------------------------------------------------------------- */ |
47 | | /* String */ |
48 | | /* ---------------------------------------------------------------------------------------------- */ |
49 | | |
50 | | /** |
51 | | * Appends an unsigned numeric value to the given string. |
52 | | * |
53 | | * @param formatter A pointer to the `ZydisFormatter` instance. |
54 | | * @param base The numeric base. |
55 | | * @param str The destination string. |
56 | | * @param value The value to append. |
57 | | * @param padding_length The padding length. |
58 | | * @param force_leading_number Enable this option to prepend a leading `0` if the first |
59 | | * character is non-numeric. |
60 | | */ |
61 | | #define ZYDIS_STRING_APPEND_NUM_U(formatter, base, str, value, padding_length, \ |
62 | | force_leading_number) \ |
63 | 0 | switch (base) \ |
64 | 0 | { \ |
65 | 0 | case ZYDIS_NUMERIC_BASE_DEC: \ |
66 | 0 | ZYAN_CHECK(ZydisStringAppendDecU(str, value, padding_length, \ |
67 | 0 | (formatter)->number_format[base][0].string, \ |
68 | 0 | (formatter)->number_format[base][1].string)); \ |
69 | 0 | break; \ |
70 | 0 | case ZYDIS_NUMERIC_BASE_HEX: \ |
71 | 0 | ZYAN_CHECK(ZydisStringAppendHexU(str, value, padding_length, force_leading_number, \ |
72 | 0 | (formatter)->hex_uppercase, \ |
73 | 0 | (formatter)->number_format[base][0].string, \ |
74 | 0 | (formatter)->number_format[base][1].string)); \ |
75 | 0 | break; \ |
76 | 0 | default: \ |
77 | 0 | return ZYAN_STATUS_INVALID_ARGUMENT; \ |
78 | 0 | } |
79 | | |
80 | | /** |
81 | | * Appends a signed numeric value to the given string. |
82 | | * |
83 | | * @param formatter A pointer to the `ZydisFormatter` instance. |
84 | | * @param base The numeric base. |
85 | | * @param str The destination string. |
86 | | * @param value The value to append. |
87 | | * @param padding_length The padding length. |
88 | | * @param force_leading_number Enable this option to prepend a leading `0`, if the first |
89 | | * character is non-numeric. |
90 | | * @param force_sign Enable to print the '+' sign for positive numbers. |
91 | | */ |
92 | | #define ZYDIS_STRING_APPEND_NUM_S(formatter, base, str, value, padding_length, \ |
93 | | force_leading_number, force_sign) \ |
94 | 0 | switch (base) \ |
95 | 0 | { \ |
96 | 0 | case ZYDIS_NUMERIC_BASE_DEC: \ |
97 | 0 | ZYAN_CHECK(ZydisStringAppendDecS(str, value, padding_length, force_sign, \ |
98 | 0 | (formatter)->number_format[base][0].string, \ |
99 | 0 | (formatter)->number_format[base][1].string)); \ |
100 | 0 | break; \ |
101 | 0 | case ZYDIS_NUMERIC_BASE_HEX: \ |
102 | 0 | ZYAN_CHECK(ZydisStringAppendHexS(str, value, padding_length, force_leading_number, \ |
103 | 0 | (formatter)->hex_uppercase, force_sign, \ |
104 | 0 | (formatter)->number_format[base][0].string, \ |
105 | 0 | (formatter)->number_format[base][1].string)); \ |
106 | 0 | break; \ |
107 | 0 | default: \ |
108 | 0 | return ZYAN_STATUS_INVALID_ARGUMENT; \ |
109 | 0 | } |
110 | | |
111 | | /* ---------------------------------------------------------------------------------------------- */ |
112 | | /* Buffer */ |
113 | | /* ---------------------------------------------------------------------------------------------- */ |
114 | | |
115 | | /** |
116 | | * Invokes the `ZydisFormatterBufferAppend` routine, if tokenization is enabled for the |
117 | | * current pass. |
118 | | * |
119 | | * @param buffer A pointer to the `ZydisFormatterBuffer` struct. |
120 | | * @param type The token type. |
121 | | * |
122 | | * Using this macro instead of direct calls to `ZydisFormatterBufferAppend` greatly improves the |
123 | | * performance for non-tokenizing passes. |
124 | | */ |
125 | | #define ZYDIS_BUFFER_APPEND_TOKEN(buffer, type) \ |
126 | 0 | if ((buffer)->is_token_list) \ |
127 | 0 | { \ |
128 | 0 | ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, type)); \ |
129 | 0 | } |
130 | | |
131 | | /** |
132 | | * Returns a snapshot of the buffer-state. |
133 | | * |
134 | | * @param buffer A pointer to the `ZydisFormatterBuffer` struct. |
135 | | * @param state Receives a snapshot of the buffer-state. |
136 | | * |
137 | | * Using this macro instead of direct calls to `ZydisFormatterBufferRemember` improves the |
138 | | * performance for non-tokenizing passes. |
139 | | */ |
140 | | #define ZYDIS_BUFFER_REMEMBER(buffer, state) \ |
141 | 0 | if ((buffer)->is_token_list) \ |
142 | 0 | { \ |
143 | 0 | (state) = (ZyanUPointer)(buffer)->string.vector.data; \ |
144 | 0 | } else \ |
145 | 0 | { \ |
146 | 0 | (state) = (ZyanUPointer)(buffer)->string.vector.size; \ |
147 | 0 | } |
148 | | |
149 | | /** |
150 | | * Appends a string (`STR_`-prefix) or a predefined token-list (`TOK_`-prefix). |
151 | | * |
152 | | * @param buffer A pointer to the `ZydisFormatterBuffer` struct. |
153 | | * @param name The base name (without prefix) of the string- or token. |
154 | | */ |
155 | | #define ZYDIS_BUFFER_APPEND(buffer, name) \ |
156 | 0 | if ((buffer)->is_token_list) \ |
157 | 0 | { \ |
158 | 0 | ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \ |
159 | 0 | } else \ |
160 | 0 | { \ |
161 | 0 | ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_ ## name)); \ |
162 | 0 | } |
163 | | |
164 | | // TODO: Implement `letter_case` for predefined tokens |
165 | | |
166 | | /** |
167 | | * Appends a string (`STR_`-prefix) or a predefined token-list (`TOK_`-prefix). |
168 | | * |
169 | | * @param buffer A pointer to the `ZydisFormatterBuffer` struct. |
170 | | * @param name The base name (without prefix) of the string- or token. |
171 | | * @param letter_case The desired letter-case. |
172 | | */ |
173 | | #define ZYDIS_BUFFER_APPEND_CASE(buffer, name, letter_case) \ |
174 | 0 | if ((buffer)->is_token_list) \ |
175 | 0 | { \ |
176 | 0 | ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \ |
177 | 0 | } else \ |
178 | 0 | { \ |
179 | 0 | ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string, &STR_ ## name, letter_case)); \ |
180 | 0 | } |
181 | | |
182 | | /* ---------------------------------------------------------------------------------------------- */ |
183 | | |
184 | | /* ============================================================================================== */ |
185 | | /* Helper functions */ |
186 | | /* ============================================================================================== */ |
187 | | |
188 | | /* ---------------------------------------------------------------------------------------------- */ |
189 | | /* Buffer */ |
190 | | /* ---------------------------------------------------------------------------------------------- */ |
191 | | |
192 | | // MSVC does not like the C99 flexible-array extension |
193 | | #ifdef ZYAN_MSVC |
194 | | # pragma warning(push) |
195 | | # pragma warning(disable:4200) |
196 | | #endif |
197 | | |
198 | | #pragma pack(push, 1) |
199 | | |
200 | | typedef struct ZydisPredefinedToken_ |
201 | | { |
202 | | ZyanU8 size; |
203 | | ZyanU8 next; |
204 | | ZyanU8 data[]; |
205 | | } ZydisPredefinedToken; |
206 | | |
207 | | #pragma pack(pop) |
208 | | |
209 | | #ifdef ZYAN_MSVC |
210 | | # pragma warning(pop) |
211 | | #endif |
212 | | |
213 | | /** |
214 | | * Appends a predefined token-list to the `buffer`. |
215 | | * |
216 | | * @param buffer A pointer to the `ZydisFormatterBuffer` struct. |
217 | | * @param data A pointer to the `ZydisPredefinedToken` struct. |
218 | | * |
219 | | * @return A zycore status code. |
220 | | * |
221 | | * This function is internally used to improve performance while adding static strings or multiple |
222 | | * tokens at once. |
223 | | */ |
224 | | ZYAN_INLINE ZyanStatus ZydisFormatterBufferAppendPredefined(ZydisFormatterBuffer* buffer, |
225 | | const ZydisPredefinedToken* data) |
226 | 0 | { |
227 | 0 | ZYAN_ASSERT(buffer); |
228 | 0 | ZYAN_ASSERT(data); |
229 | | |
230 | | // TODO: Merge with last token, if `last->type == predefined->first_token.type` |
231 | | |
232 | 0 | const ZyanUSize len = buffer->string.vector.size; |
233 | 0 | ZYAN_ASSERT((len > 0) && (len < 256)); |
234 | 0 | if (buffer->capacity <= len + data->size) |
235 | 0 | { |
236 | 0 | return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; |
237 | 0 | } |
238 | | |
239 | 0 | ZydisFormatterToken* const last = (ZydisFormatterToken*)buffer->string.vector.data - 1; |
240 | 0 | last->next = (ZyanU8)len; |
241 | |
|
242 | 0 | ZYAN_MEMCPY((ZyanU8*)buffer->string.vector.data + len, &data->data[0], data->size); |
243 | |
|
244 | 0 | const ZyanUSize delta = len + data->next; |
245 | 0 | buffer->capacity -= delta; |
246 | 0 | buffer->string.vector.data = (ZyanU8*)buffer->string.vector.data + delta; |
247 | 0 | buffer->string.vector.size = data->size - data->next; |
248 | 0 | buffer->string.vector.capacity = ZYAN_MIN(buffer->capacity, 255); |
249 | |
|
250 | 0 | return ZYAN_STATUS_SUCCESS; |
251 | 0 | } Unexecuted instantiation: Formatter.c:ZydisFormatterBufferAppendPredefined Unexecuted instantiation: FormatterATT.c:ZydisFormatterBufferAppendPredefined Unexecuted instantiation: FormatterBase.c:ZydisFormatterBufferAppendPredefined Unexecuted instantiation: FormatterIntel.c:ZydisFormatterBufferAppendPredefined |
252 | | |
253 | | /* ---------------------------------------------------------------------------------------------- */ |
254 | | /* General */ |
255 | | /* ---------------------------------------------------------------------------------------------- */ |
256 | | |
257 | | /** |
258 | | * Returns the size to be used as explicit size suffix (`AT&T`) or explicit typecast |
259 | | * (`INTEL`), if required. |
260 | | * |
261 | | * @param formatter A pointer to the `ZydisFormatter` instance. |
262 | | * @param context A pointer to the `ZydisFormatterContext` struct. |
263 | | * @param operand The instructions first memory operand. |
264 | | * |
265 | | * @return Returns the explicit size, if required, or `0`, if not needed. |
266 | | * |
267 | | * This function always returns a size different to `0`, if the `ZYDIS_FORMATTER_PROP_FORCE_SIZE` |
268 | | * is set to `ZYAN_TRUE`. |
269 | | */ |
270 | | ZyanU32 ZydisFormatterHelperGetExplicitSize(const ZydisFormatter* formatter, |
271 | | ZydisFormatterContext* context, const ZydisDecodedOperand* operand); |
272 | | |
273 | | /* ---------------------------------------------------------------------------------------------- */ |
274 | | |
275 | | /* ============================================================================================== */ |
276 | | /* Formatter functions */ |
277 | | /* ============================================================================================== */ |
278 | | |
279 | | /* ---------------------------------------------------------------------------------------------- */ |
280 | | /* Operands */ |
281 | | /* ---------------------------------------------------------------------------------------------- */ |
282 | | |
283 | | ZyanStatus ZydisFormatterBaseFormatOperandREG(const ZydisFormatter* formatter, |
284 | | ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); |
285 | | |
286 | | ZyanStatus ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter* formatter, |
287 | | ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); |
288 | | |
289 | | ZyanStatus ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter* formatter, |
290 | | ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); |
291 | | |
292 | | /* ---------------------------------------------------------------------------------------------- */ |
293 | | /* Elemental tokens */ |
294 | | /* ---------------------------------------------------------------------------------------------- */ |
295 | | |
296 | | ZyanStatus ZydisFormatterBasePrintAddressABS(const ZydisFormatter* formatter, |
297 | | ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); |
298 | | |
299 | | ZyanStatus ZydisFormatterBasePrintAddressREL(const ZydisFormatter* formatter, |
300 | | ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); |
301 | | |
302 | | ZyanStatus ZydisFormatterBasePrintIMM(const ZydisFormatter* formatter, |
303 | | ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); |
304 | | |
305 | | /* ---------------------------------------------------------------------------------------------- */ |
306 | | /* Optional tokens */ |
307 | | /* ---------------------------------------------------------------------------------------------- */ |
308 | | |
309 | | ZyanStatus ZydisFormatterBasePrintSegment(const ZydisFormatter* formatter, |
310 | | ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); |
311 | | |
312 | | ZyanStatus ZydisFormatterBasePrintPrefixes(const ZydisFormatter* formatter, |
313 | | ZydisFormatterBuffer* buffer, ZydisFormatterContext* context); |
314 | | |
315 | | ZyanStatus ZydisFormatterBasePrintDecorator(const ZydisFormatter* formatter, |
316 | | ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator); |
317 | | |
318 | | /* ---------------------------------------------------------------------------------------------- */ |
319 | | |
320 | | /* ============================================================================================== */ |
321 | | |
322 | | #ifdef __cplusplus |
323 | | } |
324 | | #endif |
325 | | |
326 | | #endif // ZYDIS_FORMATTER_BASE_H |