xref: /haiku/headers/libs/zydis/Zydis/Internal/FormatterBase.h (revision caed67a8cba83913b9c21ac2b06ebc6bd1cb3111)
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     switch (base) \
64     { \
65     case ZYDIS_NUMERIC_BASE_DEC: \
66         ZYAN_CHECK(ZydisStringAppendDecU(str, value, padding_length, \
67             (formatter)->number_format[base][0].string, \
68             (formatter)->number_format[base][1].string)); \
69         break; \
70     case ZYDIS_NUMERIC_BASE_HEX: \
71         ZYAN_CHECK(ZydisStringAppendHexU(str, value, padding_length, force_leading_number, \
72             (formatter)->hex_uppercase, \
73             (formatter)->number_format[base][0].string, \
74             (formatter)->number_format[base][1].string)); \
75         break; \
76     default: \
77         return ZYAN_STATUS_INVALID_ARGUMENT; \
78     }
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     switch (base) \
95     { \
96     case ZYDIS_NUMERIC_BASE_DEC: \
97         ZYAN_CHECK(ZydisStringAppendDecS(str, value, padding_length, force_sign, \
98             (formatter)->number_format[base][0].string, \
99             (formatter)->number_format[base][1].string)); \
100         break; \
101     case ZYDIS_NUMERIC_BASE_HEX: \
102         ZYAN_CHECK(ZydisStringAppendHexS(str, value, padding_length, force_leading_number,  \
103             (formatter)->hex_uppercase, force_sign, \
104             (formatter)->number_format[base][0].string, \
105             (formatter)->number_format[base][1].string)); \
106         break; \
107     default: \
108         return ZYAN_STATUS_INVALID_ARGUMENT; \
109     }
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     if ((buffer)->is_token_list) \
127     { \
128         ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, type)); \
129     }
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     if ((buffer)->is_token_list) \
142     { \
143         (state) = (ZyanUPointer)(buffer)->string.vector.data; \
144     } else \
145     { \
146         (state) = (ZyanUPointer)(buffer)->string.vector.size; \
147     }
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     if ((buffer)->is_token_list) \
157     { \
158         ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \
159     } else \
160     { \
161         ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_ ## name)); \
162     }
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     if ((buffer)->is_token_list) \
175     { \
176         ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \
177     } else \
178     { \
179         ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string, &STR_ ## name, letter_case)); \
180     }
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 {
227     ZYAN_ASSERT(buffer);
228     ZYAN_ASSERT(data);
229 
230     const ZyanUSize len = buffer->string.vector.size;
231     ZYAN_ASSERT((len > 0) && (len < 256));
232     if (buffer->capacity <= len + data->size)
233     {
234         return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
235     }
236 
237     ZydisFormatterToken* const last = (ZydisFormatterToken*)buffer->string.vector.data - 1;
238     last->next = (ZyanU8)len;
239 
240     ZYAN_MEMCPY((ZyanU8*)buffer->string.vector.data + len, &data->data[0], data->size);
241 
242     const ZyanUSize delta = len + data->next;
243     buffer->capacity -= delta;
244     buffer->string.vector.data = (ZyanU8*)buffer->string.vector.data + delta;
245     buffer->string.vector.size = data->size - data->next;
246     buffer->string.vector.capacity = ZYAN_MIN(buffer->capacity, 255);
247 
248     return ZYAN_STATUS_SUCCESS;
249 }
250 
251 /* ---------------------------------------------------------------------------------------------- */
252 /* General                                                                                        */
253 /* ---------------------------------------------------------------------------------------------- */
254 
255 /**
256  * Returns the size to be used as explicit size suffix (`AT&T`) or explicit typecast
257  * (`INTEL`), if required.
258  *
259  * @param   formatter   A pointer to the `ZydisFormatter` instance.
260  * @param   context     A pointer to the `ZydisFormatterContext` struct.
261  * @param   operand     The instructions first memory operand.
262  *
263  * @return  Returns the explicit size, if required, or `0`, if not needed.
264  *
265  * This function always returns a size different to `0`, if the `ZYDIS_FORMATTER_PROP_FORCE_SIZE`
266  * is set to `ZYAN_TRUE`.
267  */
268 ZyanU32 ZydisFormatterHelperGetExplicitSize(const ZydisFormatter* formatter,
269     ZydisFormatterContext* context, const ZydisDecodedOperand* operand);
270 
271 /* ---------------------------------------------------------------------------------------------- */
272 
273 /* ============================================================================================== */
274 /* Formatter functions                                                                            */
275 /* ============================================================================================== */
276 
277 /* ---------------------------------------------------------------------------------------------- */
278 /* Operands                                                                                       */
279 /* ---------------------------------------------------------------------------------------------- */
280 
281 ZyanStatus ZydisFormatterBaseFormatOperandREG(const ZydisFormatter* formatter,
282     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
283 
284 ZyanStatus ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter* formatter,
285     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
286 
287 ZyanStatus ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter* formatter,
288     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
289 
290 /* ---------------------------------------------------------------------------------------------- */
291 /* Elemental tokens                                                                               */
292 /* ---------------------------------------------------------------------------------------------- */
293 
294 ZyanStatus ZydisFormatterBasePrintAddressABS(const ZydisFormatter* formatter,
295     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
296 
297 ZyanStatus ZydisFormatterBasePrintAddressREL(const ZydisFormatter* formatter,
298     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
299 
300 ZyanStatus ZydisFormatterBasePrintIMM(const ZydisFormatter* formatter,
301     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
302 
303 /* ---------------------------------------------------------------------------------------------- */
304 /* Optional tokens                                                                                */
305 /* ---------------------------------------------------------------------------------------------- */
306 
307 ZyanStatus ZydisFormatterBasePrintSegment(const ZydisFormatter* formatter,
308     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
309 
310 ZyanStatus ZydisFormatterBasePrintPrefixes(const ZydisFormatter* formatter,
311     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
312 
313 ZyanStatus ZydisFormatterBasePrintDecorator(const ZydisFormatter* formatter,
314     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator);
315 
316 /* ---------------------------------------------------------------------------------------------- */
317 
318 /* ============================================================================================== */
319 
320 #ifdef __cplusplus
321 }
322 #endif
323 
324 #endif // ZYDIS_FORMATTER_BASE_H
325