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 * @brief 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 * @brief 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.
57 * @param padding_length The padding length.
58 */
59 #define ZYDIS_STRING_APPEND_NUM_U(formatter, base, str, value, padding_length) \
60 switch (base) \
61 { \
62 case ZYDIS_NUMERIC_BASE_DEC: \
63 ZYAN_CHECK(ZydisStringAppendDecU(str, value, padding_length, \
64 (formatter)->number_format[base][0].string, \
65 (formatter)->number_format[base][1].string)); \
66 break; \
67 case ZYDIS_NUMERIC_BASE_HEX: \
68 ZYAN_CHECK(ZydisStringAppendHexU(str, value, padding_length, \
69 (formatter)->hex_uppercase, \
70 (formatter)->number_format[base][0].string, \
71 (formatter)->number_format[base][1].string)); \
72 break; \
73 default: \
74 return ZYAN_STATUS_INVALID_ARGUMENT; \
75 }
76
77 /**
78 * @brief Appends a signed numeric value to the given string.
79 *
80 * @param formatter A pointer to the `ZydisFormatter` instance.
81 * @param base The numeric base.
82 * @param str The destination string.
83 * @param value The value.
84 * @param padding_length The padding length.
85 * @param force_sign Forces printing of the '+' sign for positive numbers.
86 */
87 #define ZYDIS_STRING_APPEND_NUM_S(formatter, base, str, value, padding_length, force_sign) \
88 switch (base) \
89 { \
90 case ZYDIS_NUMERIC_BASE_DEC: \
91 ZYAN_CHECK(ZydisStringAppendDecS(str, value, padding_length, force_sign, \
92 (formatter)->number_format[base][0].string, \
93 (formatter)->number_format[base][1].string)); \
94 break; \
95 case ZYDIS_NUMERIC_BASE_HEX: \
96 ZYAN_CHECK(ZydisStringAppendHexS(str, value, padding_length, \
97 (formatter)->hex_uppercase, force_sign, \
98 (formatter)->number_format[base][0].string, \
99 (formatter)->number_format[base][1].string)); \
100 break; \
101 default: \
102 return ZYAN_STATUS_INVALID_ARGUMENT; \
103 }
104
105 /* ---------------------------------------------------------------------------------------------- */
106 /* Buffer */
107 /* ---------------------------------------------------------------------------------------------- */
108
109 /**
110 * @brief Invokes the `ZydisFormatterBufferAppend` routine, if tokenization is enabled for the
111 * current pass.
112 *
113 * @param buffer A pointer to the `ZydisFormatterBuffer` struct.
114 * @param type The token type.
115 *
116 * Using this macro instead of direct calls to `ZydisFormatterBufferAppend` greatly improves the
117 * performance for non-tokenizing passes.
118 */
119 #define ZYDIS_BUFFER_APPEND_TOKEN(buffer, type) \
120 if ((buffer)->is_token_list) \
121 { \
122 ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, type)); \
123 }
124
125 /**
126 * @brief Returns a snapshot of the buffer-state.
127 *
128 * @param buffer A pointer to the `ZydisFormatterBuffer` struct.
129 * @param state Receives a snapshot of the buffer-state.
130 *
131 * Using this macro instead of direct calls to `ZydisFormatterBufferRemember` improves the
132 * performance for non-tokenizing passes.
133 */
134 #define ZYDIS_BUFFER_REMEMBER(buffer, state) \
135 if ((buffer)->is_token_list) \
136 { \
137 (state) = (ZyanUPointer)(buffer)->string.vector.data; \
138 } else \
139 { \
140 (state) = (ZyanUPointer)(buffer)->string.vector.size; \
141 }
142
143 /**
144 * @brief Appends a string (`STR_`-prefix) or a predefined token-list (`TOK_`-prefix).
145 *
146 * @brief buffer A pointer to the `ZydisFormatterBuffer` struct.
147 * @brief name The base name (without prefix) of the string- or token.
148 */
149 #define ZYDIS_BUFFER_APPEND(buffer, name) \
150 if ((buffer)->is_token_list) \
151 { \
152 ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \
153 } else \
154 { \
155 ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_ ## name)); \
156 }
157
158 // TODO: Implement `letter_case` for predefined tokens
159
160 /**
161 * @brief Appends a string (`STR_`-prefix) or a predefined token-list (`TOK_`-prefix).
162 *
163 * @brief buffer A pointer to the `ZydisFormatterBuffer` struct.
164 * @brief name The base name (without prefix) of the string- or token.
165 * @brief letter-case The desired letter-case.
166 */
167 #define ZYDIS_BUFFER_APPEND_CASE(buffer, name, letter_case) \
168 if ((buffer)->is_token_list) \
169 { \
170 ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \
171 } else \
172 { \
173 ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string, &STR_ ## name, letter_case)); \
174 }
175
176 /* ---------------------------------------------------------------------------------------------- */
177
178 /* ============================================================================================== */
179 /* Helper functions */
180 /* ============================================================================================== */
181
182 /* ---------------------------------------------------------------------------------------------- */
183 /* Buffer */
184 /* ---------------------------------------------------------------------------------------------- */
185
186 // MSVC does not like the C99 flexible-array extension
187 #ifdef ZYAN_MSVC
188 # pragma warning(push)
189 # pragma warning(disable:4200)
190 #endif
191
192 #pragma pack(push, 1)
193
194 typedef struct ZydisPredefinedToken_
195 {
196 ZyanU8 size;
197 ZyanU8 next;
198 ZyanU8 data[];
199 } ZydisPredefinedToken;
200
201 #pragma pack(pop)
202
203 #ifdef ZYAN_MSVC
204 # pragma warning(pop)
205 #endif
206
207 /**
208 * @brief Appends a predefined token-list to the `buffer`.
209 *
210 * @param buffer A pointer to the `ZydisFormatterBuffer` struct.
211 * @param data A pointer to the `ZydisPredefinedToken` struct.
212 *
213 * @return A zycore status code.
214 *
215 * This function is internally used to improve performance while adding static strings or multiple
216 * tokens at once.
217 */
ZydisFormatterBufferAppendPredefined(ZydisFormatterBuffer * buffer,const ZydisPredefinedToken * data)218 ZYAN_INLINE ZyanStatus ZydisFormatterBufferAppendPredefined(ZydisFormatterBuffer* buffer,
219 const ZydisPredefinedToken* data)
220 {
221 ZYAN_ASSERT(buffer);
222 ZYAN_ASSERT(data);
223
224 const ZyanUSize len = buffer->string.vector.size;
225 ZYAN_ASSERT((len > 0) && (len < 256));
226 if (buffer->capacity <= len + data->size)
227 {
228 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
229 }
230
231 ZydisFormatterToken* const last = (ZydisFormatterToken*)buffer->string.vector.data - 1;
232 last->next = (ZyanU8)len;
233
234 ZYAN_MEMCPY((ZyanU8*)buffer->string.vector.data + len, &data->data[0], data->size);
235
236 const ZyanUSize delta = len + data->next;
237 buffer->capacity -= delta;
238 buffer->string.vector.data = (ZyanU8*)buffer->string.vector.data + delta;
239 buffer->string.vector.size = data->size - data->next;
240 buffer->string.vector.capacity = ZYAN_MIN(buffer->capacity, 255);
241
242 return ZYAN_STATUS_SUCCESS;
243 }
244
245 /* ---------------------------------------------------------------------------------------------- */
246 /* General */
247 /* ---------------------------------------------------------------------------------------------- */
248
249 /**
250 * @brief Returns the size to be used as explicit size suffix (`AT&T`) or explicit typecast
251 * (`INTEL`), if required.
252 *
253 * @param formatter A pointer to the `ZydisFormatter` instance.
254 * @param context A pointer to the `ZydisFormatterContext` struct.
255 * @param memop_id The operand-id of the instructions first memory operand.
256 *
257 * @return Returns the explicit size, if required, or `0`, if not needed.
258 *
259 * This function always returns a size different to `0`, if the `ZYDIS_FORMATTER_PROP_FORCE_SIZE`
260 * is set to `ZYAN_TRUE`.
261 */
262 ZyanU32 ZydisFormatterHelperGetExplicitSize(const ZydisFormatter* formatter,
263 ZydisFormatterContext* context, ZyanU8 memop_id);
264
265 /* ---------------------------------------------------------------------------------------------- */
266
267 /* ============================================================================================== */
268 /* Formatter functions */
269 /* ============================================================================================== */
270
271 /* ---------------------------------------------------------------------------------------------- */
272 /* Operands */
273 /* ---------------------------------------------------------------------------------------------- */
274
275 ZyanStatus ZydisFormatterBaseFormatOperandREG(const ZydisFormatter* formatter,
276 ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
277
278 ZyanStatus ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter* formatter,
279 ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
280
281 ZyanStatus ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter* formatter,
282 ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
283
284 /* ---------------------------------------------------------------------------------------------- */
285 /* Elemental tokens */
286 /* ---------------------------------------------------------------------------------------------- */
287
288 ZyanStatus ZydisFormatterBasePrintAddressABS(const ZydisFormatter* formatter,
289 ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
290
291 ZyanStatus ZydisFormatterBasePrintAddressREL(const ZydisFormatter* formatter,
292 ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
293
294 ZyanStatus ZydisFormatterBasePrintIMM(const ZydisFormatter* formatter,
295 ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
296
297 /* ---------------------------------------------------------------------------------------------- */
298 /* Optional tokens */
299 /* ---------------------------------------------------------------------------------------------- */
300
301 ZyanStatus ZydisFormatterBasePrintSegment(const ZydisFormatter* formatter,
302 ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
303
304 ZyanStatus ZydisFormatterBasePrintPrefixes(const ZydisFormatter* formatter,
305 ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
306
307 ZyanStatus ZydisFormatterBasePrintDecorator(const ZydisFormatter* formatter,
308 ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator);
309
310 /* ---------------------------------------------------------------------------------------------- */
311
312 /* ============================================================================================== */
313
314 #ifdef __cplusplus
315 }
316 #endif
317
318 #endif // ZYDIS_FORMATTER_BASE_H
319