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 #include <Zycore/LibC.h> 28 #include <Zydis/Formatter.h> 29 #include <Zydis/Internal/FormatterATT.h> 30 #include <Zydis/Internal/FormatterIntel.h> 31 #include <Zydis/Internal/String.h> 32 33 /* ============================================================================================== */ 34 /* Constants */ 35 /* ============================================================================================== */ 36 37 /* ---------------------------------------------------------------------------------------------- */ 38 /* Formatter presets */ 39 /* ---------------------------------------------------------------------------------------------- */ 40 41 static const ZydisFormatter* const FORMATTER_PRESETS[ZYDIS_FORMATTER_STYLE_MAX_VALUE + 1] = 42 { 43 &FORMATTER_ATT, 44 &FORMATTER_INTEL, 45 &FORMATTER_INTEL_MASM 46 }; 47 48 /* ---------------------------------------------------------------------------------------------- */ 49 50 /* ============================================================================================== */ 51 /* Internal functions */ 52 /* ============================================================================================== */ 53 54 /* ---------------------------------------------------------------------------------------------- */ 55 /* Helper functions */ 56 /* ---------------------------------------------------------------------------------------------- */ 57 58 static void ZydisFormatterBufferInit(ZydisFormatterBuffer* buffer, char* user_buffer, 59 ZyanUSize length) 60 { 61 ZYAN_ASSERT(buffer); 62 ZYAN_ASSERT(user_buffer); 63 ZYAN_ASSERT(length); 64 65 buffer->is_token_list = ZYAN_FALSE; 66 buffer->capacity = 0; 67 buffer->string.flags = ZYAN_STRING_HAS_FIXED_CAPACITY; 68 buffer->string.vector.allocator = ZYAN_NULL; 69 buffer->string.vector.growth_factor = 1; 70 buffer->string.vector.shrink_threshold = 0; 71 buffer->string.vector.destructor = ZYAN_NULL; 72 buffer->string.vector.element_size = sizeof(char); 73 buffer->string.vector.size = 1; 74 buffer->string.vector.capacity = length; 75 buffer->string.vector.data = user_buffer; 76 77 *user_buffer = '\0'; 78 } 79 80 static void ZydisFormatterBufferInitTokenized(ZydisFormatterBuffer* buffer, 81 ZydisFormatterToken** first_token, void* user_buffer, ZyanUSize length) 82 { 83 ZYAN_ASSERT(buffer); 84 ZYAN_ASSERT(first_token); 85 ZYAN_ASSERT(user_buffer); 86 ZYAN_ASSERT(length); 87 88 *first_token = user_buffer; 89 (*first_token)->type = ZYDIS_TOKEN_INVALID; 90 (*first_token)->next = 0; 91 92 user_buffer = (ZyanU8*)user_buffer + sizeof(ZydisFormatterToken); 93 length -= sizeof(ZydisFormatterToken); 94 95 buffer->is_token_list = ZYAN_TRUE; 96 buffer->capacity = length; 97 buffer->string.flags = ZYAN_STRING_HAS_FIXED_CAPACITY; 98 buffer->string.vector.allocator = ZYAN_NULL; 99 buffer->string.vector.growth_factor = 1; 100 buffer->string.vector.shrink_threshold = 0; 101 buffer->string.vector.destructor = ZYAN_NULL; 102 buffer->string.vector.element_size = sizeof(char); 103 buffer->string.vector.size = 1; 104 buffer->string.vector.capacity = length; 105 buffer->string.vector.data = user_buffer; 106 107 *(char*)user_buffer = '\0'; 108 } 109 110 /* ---------------------------------------------------------------------------------------------- */ 111 112 /* ============================================================================================== */ 113 /* Exported functions */ 114 /* ============================================================================================== */ 115 116 /* ---------------------------------------------------------------------------------------------- */ 117 /* Initialization */ 118 /* ---------------------------------------------------------------------------------------------- */ 119 120 ZyanStatus ZydisFormatterInit(ZydisFormatter* formatter, ZydisFormatterStyle style) 121 { 122 if (!formatter || ((ZyanUSize)style > ZYDIS_FORMATTER_STYLE_MAX_VALUE)) 123 { 124 return ZYAN_STATUS_INVALID_ARGUMENT; 125 } 126 127 ZYAN_MEMCPY(formatter, FORMATTER_PRESETS[style], sizeof(*formatter)); 128 129 return ZYAN_STATUS_SUCCESS; 130 } 131 132 /* ---------------------------------------------------------------------------------------------- */ 133 /* Setter */ 134 /* ---------------------------------------------------------------------------------------------- */ 135 136 ZyanStatus ZydisFormatterSetProperty(ZydisFormatter* formatter, ZydisFormatterProperty property, 137 ZyanUPointer value) 138 { 139 if (!formatter) 140 { 141 return ZYAN_STATUS_INVALID_ARGUMENT; 142 } 143 144 ZydisNumericBase base = (ZydisNumericBase)(-1); 145 ZyanU8 index = 0xFF; 146 147 switch (property) 148 { 149 case ZYDIS_FORMATTER_PROP_FORCE_SIZE: 150 { 151 formatter->force_memory_size = (value) ? ZYAN_TRUE : ZYAN_FALSE; 152 break; 153 } 154 case ZYDIS_FORMATTER_PROP_FORCE_SEGMENT: 155 { 156 formatter->force_memory_segment = (value) ? ZYAN_TRUE : ZYAN_FALSE; 157 break; 158 } 159 case ZYDIS_FORMATTER_PROP_FORCE_SCALE_ONE: 160 { 161 formatter->force_memory_scale = (value) ? ZYAN_TRUE : ZYAN_FALSE; 162 break; 163 } 164 case ZYDIS_FORMATTER_PROP_FORCE_RELATIVE_BRANCHES: 165 { 166 formatter->force_relative_branches = (value) ? ZYAN_TRUE : ZYAN_FALSE; 167 break; 168 } 169 case ZYDIS_FORMATTER_PROP_FORCE_RELATIVE_RIPREL: 170 { 171 formatter->force_relative_riprel = (value) ? ZYAN_TRUE : ZYAN_FALSE; 172 break; 173 } 174 case ZYDIS_FORMATTER_PROP_PRINT_BRANCH_SIZE: 175 { 176 formatter->print_branch_size = (value) ? ZYAN_TRUE : ZYAN_FALSE; 177 break; 178 } 179 case ZYDIS_FORMATTER_PROP_DETAILED_PREFIXES: 180 { 181 formatter->detailed_prefixes = (value) ? ZYAN_TRUE : ZYAN_FALSE; 182 break; 183 } 184 case ZYDIS_FORMATTER_PROP_ADDR_BASE: 185 { 186 if (value > ZYDIS_NUMERIC_BASE_MAX_VALUE) 187 { 188 return ZYAN_STATUS_INVALID_ARGUMENT; 189 } 190 formatter->addr_base = (ZydisNumericBase)value; 191 break; 192 } 193 case ZYDIS_FORMATTER_PROP_ADDR_SIGNEDNESS: 194 { 195 if (value > ZYDIS_SIGNEDNESS_MAX_VALUE) 196 { 197 return ZYAN_STATUS_INVALID_ARGUMENT; 198 } 199 formatter->addr_signedness = (ZydisSignedness)value; 200 break; 201 } 202 case ZYDIS_FORMATTER_PROP_ADDR_PADDING_ABSOLUTE: 203 { 204 if (((ZydisPadding)value != ZYDIS_PADDING_AUTO) && 205 (value > 0xFF)) 206 { 207 return ZYAN_STATUS_INVALID_ARGUMENT; 208 } 209 formatter->addr_padding_absolute = (ZydisPadding)value; 210 break; 211 } 212 case ZYDIS_FORMATTER_PROP_ADDR_PADDING_RELATIVE: 213 { 214 if (((ZydisPadding)value != ZYDIS_PADDING_AUTO) && 215 (value > 0xFF)) 216 { 217 return ZYAN_STATUS_INVALID_ARGUMENT; 218 } 219 formatter->addr_padding_relative = (ZydisPadding)value; 220 break; 221 } 222 case ZYDIS_FORMATTER_PROP_DISP_BASE: 223 { 224 if (value > ZYDIS_NUMERIC_BASE_MAX_VALUE) 225 { 226 return ZYAN_STATUS_INVALID_ARGUMENT; 227 } 228 formatter->disp_base = (ZydisNumericBase)value; 229 break; 230 } 231 case ZYDIS_FORMATTER_PROP_DISP_SIGNEDNESS: 232 { 233 if (value > ZYDIS_SIGNEDNESS_MAX_VALUE) 234 { 235 return ZYAN_STATUS_INVALID_ARGUMENT; 236 } 237 formatter->disp_signedness = (ZydisSignedness)value; 238 break; 239 } 240 case ZYDIS_FORMATTER_PROP_DISP_PADDING: 241 { 242 if ((ZydisPadding)value == ZYDIS_PADDING_AUTO) 243 { 244 if ((ZyanUSize)formatter->style > ZYDIS_FORMATTER_STYLE_MAX_VALUE) 245 { 246 return ZYAN_STATUS_INVALID_ARGUMENT; 247 } 248 formatter->disp_padding = FORMATTER_PRESETS[formatter->style]->disp_padding; 249 } 250 else if (value > 0xFF) 251 { 252 return ZYAN_STATUS_INVALID_ARGUMENT; 253 } 254 formatter->disp_padding = (ZydisPadding)value; 255 break; 256 } 257 case ZYDIS_FORMATTER_PROP_IMM_BASE: 258 { 259 if (value > ZYDIS_NUMERIC_BASE_MAX_VALUE) 260 { 261 return ZYAN_STATUS_INVALID_ARGUMENT; 262 } 263 formatter->imm_base = (ZydisNumericBase)value; 264 break; 265 } 266 case ZYDIS_FORMATTER_PROP_IMM_SIGNEDNESS: 267 { 268 if (value > ZYDIS_SIGNEDNESS_MAX_VALUE) 269 { 270 return ZYAN_STATUS_INVALID_ARGUMENT; 271 } 272 formatter->imm_signedness = (ZydisSignedness)value; 273 break; 274 } 275 case ZYDIS_FORMATTER_PROP_IMM_PADDING: 276 { 277 if ((ZydisPadding)value == ZYDIS_PADDING_AUTO) 278 { 279 if ((ZyanUSize)formatter->style > ZYDIS_FORMATTER_STYLE_MAX_VALUE) 280 { 281 return ZYAN_STATUS_INVALID_ARGUMENT; 282 } 283 formatter->imm_padding = FORMATTER_PRESETS[formatter->style]->imm_padding; 284 } 285 else if (value > 0xFF) 286 { 287 return ZYAN_STATUS_INVALID_ARGUMENT; 288 } 289 formatter->imm_padding = (ZydisPadding)value; 290 break; 291 } 292 case ZYDIS_FORMATTER_PROP_UPPERCASE_PREFIXES: 293 { 294 formatter->case_prefixes = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT; 295 break; 296 } 297 case ZYDIS_FORMATTER_PROP_UPPERCASE_MNEMONIC: 298 { 299 formatter->case_mnemonic = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT; 300 break; 301 } 302 case ZYDIS_FORMATTER_PROP_UPPERCASE_REGISTERS: 303 { 304 formatter->case_registers = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT; 305 break; 306 } 307 case ZYDIS_FORMATTER_PROP_UPPERCASE_TYPECASTS: 308 { 309 formatter->case_typecasts = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT; 310 break; 311 } 312 case ZYDIS_FORMATTER_PROP_UPPERCASE_DECORATORS: 313 { 314 formatter->case_decorators = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT; 315 break; 316 } 317 case ZYDIS_FORMATTER_PROP_DEC_PREFIX: 318 { 319 base = ZYDIS_NUMERIC_BASE_DEC; 320 index = 0; 321 break; 322 } 323 case ZYDIS_FORMATTER_PROP_DEC_SUFFIX: 324 { 325 base = ZYDIS_NUMERIC_BASE_DEC; 326 index = 1; 327 break; 328 } 329 case ZYDIS_FORMATTER_PROP_HEX_UPPERCASE: 330 { 331 formatter->hex_uppercase = (value) ? ZYAN_TRUE : ZYAN_FALSE; 332 break; 333 } 334 case ZYDIS_FORMATTER_PROP_HEX_FORCE_LEADING_NUMBER: 335 { 336 formatter->hex_force_leading_number = (value) ? ZYAN_TRUE : ZYAN_FALSE; 337 break; 338 } 339 case ZYDIS_FORMATTER_PROP_HEX_PREFIX: 340 { 341 base = ZYDIS_NUMERIC_BASE_HEX; 342 index = 0; 343 break; 344 } 345 case ZYDIS_FORMATTER_PROP_HEX_SUFFIX: 346 { 347 base = ZYDIS_NUMERIC_BASE_HEX; 348 index = 1; 349 break; 350 } 351 default: 352 return ZYAN_STATUS_INVALID_ARGUMENT; 353 } 354 355 // Set prefix or suffix 356 if (base != (ZydisNumericBase)(-1)) 357 { 358 if (value) 359 { 360 const ZyanUSize len = ZYAN_STRLEN((char*)value); 361 if (len > 10) 362 { 363 return ZYAN_STATUS_INVALID_ARGUMENT; 364 } 365 ZYAN_MEMCPY(formatter->number_format[base][index].buffer, (void*)value, len); 366 formatter->number_format[base][index].buffer[len] = '\0'; 367 formatter->number_format[base][index].string_data.string.vector.data = 368 formatter->number_format[base][index].buffer; 369 formatter->number_format[base][index].string_data.string.vector.size = len + 1; 370 formatter->number_format[base][index].string = 371 &formatter->number_format[base][index].string_data; 372 } else 373 { 374 formatter->number_format[base][index].string = ZYAN_NULL; 375 } 376 } 377 378 return ZYAN_STATUS_SUCCESS; 379 } 380 381 ZyanStatus ZydisFormatterSetHook(ZydisFormatter* formatter, ZydisFormatterFunction type, 382 const void** callback) 383 { 384 if (!formatter || !callback || ((ZyanUSize)type > ZYDIS_FORMATTER_FUNC_MAX_VALUE)) 385 { 386 return ZYAN_STATUS_INVALID_ARGUMENT; 387 } 388 389 const void* const temp = *callback; 390 391 // The following code relies on the order of the enum values and the function fields inside 392 // the `ZydisFormatter` struct 393 394 #ifdef ZYAN_DEBUG 395 const ZyanUPointer* test = (ZyanUPointer*)(&formatter->func_pre_instruction + type); 396 switch (type) 397 { 398 case ZYDIS_FORMATTER_FUNC_PRE_INSTRUCTION: 399 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_pre_instruction ); break; 400 case ZYDIS_FORMATTER_FUNC_POST_INSTRUCTION: 401 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_post_instruction ); break; 402 case ZYDIS_FORMATTER_FUNC_FORMAT_INSTRUCTION: 403 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_instruction); break; 404 case ZYDIS_FORMATTER_FUNC_PRE_OPERAND: 405 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_pre_operand ); break; 406 case ZYDIS_FORMATTER_FUNC_POST_OPERAND: 407 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_post_operand ); break; 408 case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_REG: 409 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_reg); break; 410 case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_MEM: 411 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_mem); break; 412 case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_PTR: 413 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_ptr); break; 414 case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_IMM: 415 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_imm); break; 416 case ZYDIS_FORMATTER_FUNC_PRINT_MNEMONIC: 417 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_mnemonic ); break; 418 case ZYDIS_FORMATTER_FUNC_PRINT_REGISTER: 419 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_register ); break; 420 case ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS: 421 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_address_abs ); break; 422 case ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_REL: 423 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_address_rel ); break; 424 case ZYDIS_FORMATTER_FUNC_PRINT_DISP: 425 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_disp ); break; 426 case ZYDIS_FORMATTER_FUNC_PRINT_IMM: 427 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_imm ); break; 428 case ZYDIS_FORMATTER_FUNC_PRINT_TYPECAST: 429 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_typecast ); break; 430 case ZYDIS_FORMATTER_FUNC_PRINT_SEGMENT: 431 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_segment ); break; 432 case ZYDIS_FORMATTER_FUNC_PRINT_PREFIXES: 433 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_prefixes ); break; 434 case ZYDIS_FORMATTER_FUNC_PRINT_DECORATOR: 435 ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_decorator ); break; 436 default: 437 ZYAN_UNREACHABLE; 438 } 439 #endif 440 441 *callback = *(const void**)(&formatter->func_pre_instruction + type); 442 if (!temp) 443 { 444 return ZYAN_STATUS_SUCCESS; 445 } 446 ZYAN_MEMCPY(&formatter->func_pre_instruction + type, &temp, sizeof(ZyanUPointer)); 447 448 return ZYAN_STATUS_SUCCESS; 449 } 450 451 /* ---------------------------------------------------------------------------------------------- */ 452 /* Formatting */ 453 /* ---------------------------------------------------------------------------------------------- */ 454 455 ZyanStatus ZydisFormatterFormatInstruction(const ZydisFormatter* formatter, 456 const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operands, 457 ZyanU8 operand_count, char* buffer, ZyanUSize length, ZyanU64 runtime_address, void* user_data) 458 { 459 if (!formatter || !instruction || (operand_count && !operands) || 460 (operand_count > ZYDIS_MAX_OPERAND_COUNT) || 461 (operand_count < instruction->operand_count_visible) || !buffer || (length == 0)) 462 { 463 return ZYAN_STATUS_INVALID_ARGUMENT; 464 } 465 466 ZydisFormatterBuffer formatter_buffer; 467 ZydisFormatterBufferInit(&formatter_buffer, buffer, length); 468 469 ZydisFormatterContext context; 470 context.instruction = instruction; 471 context.operands = operands; 472 context.runtime_address = runtime_address; 473 context.operand = ZYAN_NULL; 474 context.user_data = user_data; 475 476 if (formatter->func_pre_instruction) 477 { 478 ZYAN_CHECK(formatter->func_pre_instruction(formatter, &formatter_buffer, &context)); 479 } 480 481 ZYAN_CHECK(formatter->func_format_instruction(formatter, &formatter_buffer, &context)); 482 483 if (formatter->func_post_instruction) 484 { 485 ZYAN_CHECK(formatter->func_post_instruction(formatter, &formatter_buffer, &context)); 486 } 487 488 return ZYAN_STATUS_SUCCESS; 489 } 490 491 ZyanStatus ZydisFormatterFormatOperand(const ZydisFormatter* formatter, 492 const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand, 493 char* buffer, ZyanUSize length, ZyanU64 runtime_address, void* user_data) 494 { 495 if (!formatter || !instruction || !operand || !buffer || (length == 0)) 496 { 497 return ZYAN_STATUS_INVALID_ARGUMENT; 498 } 499 500 ZydisFormatterBuffer formatter_buffer; 501 ZydisFormatterBufferInit(&formatter_buffer, buffer, length); 502 503 ZydisFormatterContext context; 504 context.instruction = instruction; 505 context.operands = ZYAN_NULL; 506 context.runtime_address = runtime_address; 507 context.operand = operand; 508 context.user_data = user_data; 509 510 // We ignore `ZYDIS_STATUS_SKIP_TOKEN` for all operand-functions as it does not make any sense 511 // to skip the only operand printed by this function 512 513 if (formatter->func_pre_operand) 514 { 515 ZYAN_CHECK(formatter->func_pre_operand(formatter, &formatter_buffer, &context)); 516 } 517 518 switch (context.operand->type) 519 { 520 case ZYDIS_OPERAND_TYPE_REGISTER: 521 ZYAN_CHECK(formatter->func_format_operand_reg(formatter, &formatter_buffer, &context)); 522 break; 523 case ZYDIS_OPERAND_TYPE_MEMORY: 524 ZYAN_CHECK(formatter->func_format_operand_mem(formatter, &formatter_buffer, &context)); 525 break; 526 case ZYDIS_OPERAND_TYPE_IMMEDIATE: 527 ZYAN_CHECK(formatter->func_format_operand_imm(formatter, &formatter_buffer, &context)); 528 break; 529 case ZYDIS_OPERAND_TYPE_POINTER: 530 ZYAN_CHECK(formatter->func_format_operand_ptr(formatter, &formatter_buffer, &context)); 531 break; 532 default: 533 return ZYAN_STATUS_INVALID_ARGUMENT; 534 } 535 536 if (formatter->func_post_operand) 537 { 538 ZYAN_CHECK(formatter->func_post_operand(formatter, &formatter_buffer, &context)); 539 } 540 541 return ZYAN_STATUS_SUCCESS; 542 } 543 544 /* ---------------------------------------------------------------------------------------------- */ 545 /* Tokenizing */ 546 /* ---------------------------------------------------------------------------------------------- */ 547 548 ZyanStatus ZydisFormatterTokenizeInstruction(const ZydisFormatter* formatter, 549 const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operands, 550 ZyanU8 operand_count, void* buffer, ZyanUSize length, ZyanU64 runtime_address, 551 ZydisFormatterTokenConst** token, void* user_data) 552 { 553 if (!formatter || !instruction || (operand_count && !operands) || 554 (operand_count > ZYDIS_MAX_OPERAND_COUNT) || 555 (operand_count < instruction->operand_count_visible) || !buffer || 556 (length <= sizeof(ZydisFormatterToken)) || !token) 557 { 558 return ZYAN_STATUS_INVALID_ARGUMENT; 559 } 560 561 ZydisFormatterBuffer formatter_buffer; 562 ZydisFormatterToken* first_token; 563 ZydisFormatterBufferInitTokenized(&formatter_buffer, &first_token, buffer, length); 564 565 ZydisFormatterContext context; 566 context.instruction = instruction; 567 context.operands = operands; 568 context.runtime_address = runtime_address; 569 context.operand = ZYAN_NULL; 570 context.user_data = user_data; 571 572 if (formatter->func_pre_instruction) 573 { 574 ZYAN_CHECK(formatter->func_pre_instruction(formatter, &formatter_buffer, &context)); 575 } 576 577 ZYAN_CHECK(formatter->func_format_instruction(formatter, &formatter_buffer, &context)); 578 579 if (formatter->func_post_instruction) 580 { 581 ZYAN_CHECK(formatter->func_post_instruction(formatter, &formatter_buffer, &context)); 582 } 583 584 if (first_token->next) 585 { 586 *token = (ZydisFormatterTokenConst*)((ZyanU8*)first_token + sizeof(ZydisFormatterToken) + 587 first_token->next); 588 return ZYAN_STATUS_SUCCESS; 589 } 590 591 *token = first_token; 592 return ZYAN_STATUS_SUCCESS; 593 } 594 595 ZyanStatus ZydisFormatterTokenizeOperand(const ZydisFormatter* formatter, 596 const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand, 597 void* buffer, ZyanUSize length, ZyanU64 runtime_address, ZydisFormatterTokenConst** token, 598 void* user_data) 599 { 600 if (!formatter || !instruction || !operand || !buffer || 601 (length <= sizeof(ZydisFormatterToken)) || !token) 602 { 603 return ZYAN_STATUS_INVALID_ARGUMENT; 604 } 605 606 ZydisFormatterToken* first_token; 607 ZydisFormatterBuffer formatter_buffer; 608 ZydisFormatterBufferInitTokenized(&formatter_buffer, &first_token, buffer, length); 609 610 ZydisFormatterContext context; 611 context.instruction = instruction; 612 context.operands = ZYAN_NULL; 613 context.runtime_address = runtime_address; 614 context.operand = operand; 615 context.user_data = user_data; 616 617 // We ignore `ZYDIS_STATUS_SKIP_TOKEN` for all operand-functions as it does not make any sense 618 // to skip the only operand printed by this function 619 620 if (formatter->func_pre_operand) 621 { 622 ZYAN_CHECK(formatter->func_pre_operand(formatter, &formatter_buffer, &context)); 623 } 624 625 switch (context.operand->type) 626 { 627 case ZYDIS_OPERAND_TYPE_REGISTER: 628 ZYAN_CHECK(formatter->func_format_operand_reg(formatter, &formatter_buffer, &context)); 629 break; 630 case ZYDIS_OPERAND_TYPE_MEMORY: 631 ZYAN_CHECK(formatter->func_format_operand_mem(formatter, &formatter_buffer, &context)); 632 break; 633 case ZYDIS_OPERAND_TYPE_IMMEDIATE: 634 ZYAN_CHECK(formatter->func_format_operand_imm(formatter, &formatter_buffer, &context)); 635 break; 636 case ZYDIS_OPERAND_TYPE_POINTER: 637 ZYAN_CHECK(formatter->func_format_operand_ptr(formatter, &formatter_buffer, &context)); 638 break; 639 default: 640 return ZYAN_STATUS_INVALID_ARGUMENT; 641 } 642 643 if (formatter->func_post_operand) 644 { 645 ZYAN_CHECK(formatter->func_post_operand(formatter, &formatter_buffer, &context)); 646 } 647 648 if (first_token->next) 649 { 650 *token = (ZydisFormatterTokenConst*)((ZyanU8*)first_token + sizeof(ZydisFormatterToken) + 651 first_token->next); 652 return ZYAN_STATUS_SUCCESS; 653 } 654 655 *token = first_token; 656 return ZYAN_STATUS_SUCCESS; 657 } 658 659 /* ============================================================================================== */ 660 661 /* ============================================================================================== */ 662