duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

Segment.c (6993B)


      1 /***************************************************************************************************
      2 
      3   Zyan Disassembler Library (Zydis)
      4 
      5   Original Author : Florian Bernd
      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/Segment.h>
     29 
     30 /* ============================================================================================== */
     31 /* Exported functions                                                                             */
     32 /* ============================================================================================== */
     33 
     34 ZyanStatus ZydisGetInstructionSegments(const ZydisDecodedInstruction* instruction,
     35     ZydisInstructionSegments* segments)
     36 {
     37     if (!instruction || !segments)
     38     {
     39         return ZYAN_STATUS_INVALID_ARGUMENT;
     40     }
     41 
     42     ZYAN_MEMSET(segments, 0, sizeof(*segments));
     43 
     44     // Legacy prefixes and `REX`
     45     if (instruction->raw.prefix_count)
     46     {
     47         const ZyanU8 rex_offset = (instruction->attributes & ZYDIS_ATTRIB_HAS_REX) ? 1 : 0;
     48         if (!rex_offset || (instruction->raw.prefix_count > 1))
     49         {
     50             segments->segments[segments->count  ].type   = ZYDIS_INSTR_SEGMENT_PREFIXES;
     51             segments->segments[segments->count  ].offset = 0;
     52             segments->segments[segments->count++].size   =
     53                 instruction->raw.prefix_count - rex_offset;
     54         }
     55         if (rex_offset)
     56         {
     57             segments->segments[segments->count  ].type   = ZYDIS_INSTR_SEGMENT_REX;
     58             segments->segments[segments->count  ].offset =
     59                 instruction->raw.prefix_count - rex_offset;
     60             segments->segments[segments->count++].size   = 1;
     61         }
     62     }
     63 
     64     // Encoding prefixes
     65     ZydisInstructionSegment segment_type = ZYDIS_INSTR_SEGMENT_NONE;
     66     ZyanU8 segment_offset = 0;
     67     ZyanU8 segment_size = 0;
     68     switch (instruction->encoding)
     69     {
     70     case ZYDIS_INSTRUCTION_ENCODING_XOP:
     71         segment_type = ZYDIS_INSTR_SEGMENT_XOP;
     72         segment_offset = instruction->raw.xop.offset;
     73         segment_size = 3;
     74         break;
     75     case ZYDIS_INSTRUCTION_ENCODING_VEX:
     76         segment_type = ZYDIS_INSTR_SEGMENT_VEX;
     77         segment_offset = instruction->raw.vex.offset;
     78         segment_size = instruction->raw.vex.size;
     79         break;
     80     case ZYDIS_INSTRUCTION_ENCODING_EVEX:
     81         segment_type = ZYDIS_INSTR_SEGMENT_EVEX;
     82         segment_offset = instruction->raw.evex.offset;
     83         segment_size = 4;
     84         break;
     85     case ZYDIS_INSTRUCTION_ENCODING_MVEX:
     86         segment_type = ZYDIS_INSTR_SEGMENT_MVEX;
     87         segment_offset = instruction->raw.mvex.offset;
     88         segment_size = 4;
     89         break;
     90     default:
     91         break;
     92     }
     93     if (segment_type)
     94     {
     95         segments->segments[segments->count  ].type   = segment_type;
     96         segments->segments[segments->count  ].offset = segment_offset;
     97         segments->segments[segments->count++].size   = segment_size;
     98     }
     99 
    100     // Opcode
    101     segment_size = 1;
    102     if ((instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_LEGACY) ||
    103         (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_3DNOW))
    104     {
    105         switch (instruction->opcode_map)
    106         {
    107         case ZYDIS_OPCODE_MAP_DEFAULT:
    108             break;
    109         case ZYDIS_OPCODE_MAP_0F:
    110             ZYAN_FALLTHROUGH;
    111         case ZYDIS_OPCODE_MAP_0F0F:
    112             segment_size = 2;
    113             break;
    114         case ZYDIS_OPCODE_MAP_0F38:
    115             ZYAN_FALLTHROUGH;
    116         case ZYDIS_OPCODE_MAP_0F3A:
    117             segment_size = 3;
    118             break;
    119         default:
    120         ZYAN_UNREACHABLE;
    121         }
    122     }
    123     segments->segments[segments->count  ].type = ZYDIS_INSTR_SEGMENT_OPCODE;
    124     if (segments->count)
    125     {
    126         segments->segments[segments->count].offset =
    127                 segments->segments[segments->count - 1].offset +
    128                 segments->segments[segments->count - 1].size;
    129     } else
    130     {
    131         segments->segments[segments->count].offset = 0;
    132     }
    133     segments->segments[segments->count++].size = segment_size;
    134 
    135     // ModRM
    136     if (instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM)
    137     {
    138         segments->segments[segments->count  ].type = ZYDIS_INSTR_SEGMENT_MODRM;
    139         segments->segments[segments->count  ].offset = instruction->raw.modrm.offset;
    140         segments->segments[segments->count++].size = 1;
    141     }
    142 
    143     // SIB
    144     if (instruction->attributes & ZYDIS_ATTRIB_HAS_SIB)
    145     {
    146         segments->segments[segments->count  ].type = ZYDIS_INSTR_SEGMENT_SIB;
    147         segments->segments[segments->count  ].offset = instruction->raw.sib.offset;
    148         segments->segments[segments->count++].size = 1;
    149     }
    150 
    151     // Displacement
    152     if (instruction->raw.disp.size)
    153     {
    154         segments->segments[segments->count  ].type = ZYDIS_INSTR_SEGMENT_DISPLACEMENT;
    155         segments->segments[segments->count  ].offset = instruction->raw.disp.offset;
    156         segments->segments[segments->count++].size = instruction->raw.disp.size / 8;
    157     }
    158 
    159     // Immediates
    160     for (ZyanU8 i = 0; i < 2; ++i)
    161     {
    162         if (instruction->raw.imm[i].size)
    163         {
    164             segments->segments[segments->count  ].type = ZYDIS_INSTR_SEGMENT_IMMEDIATE;
    165             segments->segments[segments->count  ].offset = instruction->raw.imm[i].offset;
    166             segments->segments[segments->count++].size = instruction->raw.imm[i].size / 8;
    167         }
    168     }
    169 
    170     if (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_3DNOW)
    171     {
    172         segments->segments[segments->count].type = ZYDIS_INSTR_SEGMENT_OPCODE;
    173         segments->segments[segments->count].offset = instruction->length -1;
    174         segments->segments[segments->count++].size = 1;
    175     }
    176 
    177     return ZYAN_STATUS_SUCCESS;
    178 }
    179 
    180 /* ---------------------------------------------------------------------------------------------- */
    181 
    182 /* ============================================================================================== */