| // Copyright 2018 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package xeddata_test |
| |
| import ( |
| "fmt" |
| "log" |
| "strings" |
| |
| "golang.org/x/arch/x86/xeddata" |
| ) |
| |
| // The "testdata/xedpath" directory contains XED metadata files |
| // that are supposed to be used for Database initialization. |
| |
| // Note that XED objects in this file are not real, |
| // instructions they describe are fictional. |
| |
| // This example shows how to print raw XED objects using Reader. |
| // Objects are called "raw" because some of their fields may |
| // require additional transformations like macro (states) expansion. |
| func ExampleReader() { |
| const xedPath = "testdata/xedpath" |
| |
| input := strings.NewReader(` |
| { |
| ICLASS: VEXADD |
| EXCEPTIONS: avx-type-zero |
| CPL: 2000 |
| CATEGORY: AVX-Q |
| EXTENSION: AVX-Q |
| ATTRIBUTES: A B C |
| PATTERN: VV1 0x07 VL128 V66 V0F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM() |
| OPERANDS: REG0=XMM_R():w:width_dq:fword64 REG1=XMM_N():r:width_dq:fword64 MEM0:r:width_dq:fword64 |
| } |
| |
| { |
| ICLASS: COND_MOV_Z |
| CPL: 210 |
| CATEGORY: MOV_IF_COND_MET |
| EXTENSION: BASE |
| ISA_SET: COND_MOV |
| FLAGS: READONLY [ zf-tst ] |
| |
| PATTERN: 0x0F 0x4F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM() |
| OPERANDS: REG0=GPRv_R():cw MEM0:r:width_v |
| PATTERN: 0x0F 0x4F MOD[0b11] MOD=3 REG[rrr] RM[nnn] |
| OPERANDS: REG0=GPRv_R():cw REG1=GPRv_B():r |
| }`) |
| |
| objects, err := xeddata.NewReader(input).ReadAll() |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| for _, o := range objects { |
| fmt.Printf("%s (%s):\n", o.Opcode(), o.Extension) |
| for _, inst := range o.Insts { |
| fmt.Printf("\t[%d] %s\n", inst.Index, inst.Operands) |
| } |
| } |
| |
| //Output: |
| // VEXADD (AVX-Q): |
| // [0] REG0=XMM_R():w:width_dq:fword64 REG1=XMM_N():r:width_dq:fword64 MEM0:r:width_dq:fword64 |
| // COND_MOV_Z (BASE): |
| // [0] REG0=GPRv_R():cw MEM0:r:width_v |
| // [1] REG0=GPRv_R():cw REG1=GPRv_B():r |
| } |
| |
| // This example shows how to use ExpandStates and its effects. |
| func ExampleExpandStates() { |
| const xedPath = "testdata/xedpath" |
| |
| input := strings.NewReader(` |
| { |
| ICLASS: VEXADD |
| CPL: 3 |
| CATEGORY: ? |
| EXTENSION: ? |
| ATTRIBUTES: AT_A AT_B |
| |
| PATTERN: _M_VV_TRUE 0x58 _M_VEX_P_66 _M_VLEN_128 _M_MAP_0F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM() |
| OPERANDS: REG0=XMM_R():w:width_dq:fword64 REG1=XMM_N():r:width_dq:fword64 MEM0:r:width_dq:fword64 |
| |
| PATTERN: _M_VV_TRUE 0x58 _M_VEX_P_66 _M_VLEN_128 _M_MAP_0F MOD[0b11] MOD=3 REG[rrr] RM[nnn] |
| OPERANDS: REG0=XMM_R():w:width_dq:fword64 REG1=XMM_N():r:width_dq:fword64 REG2=XMM_B():r:width_dq:fword64 |
| |
| PATTERN: _M_VV_TRUE 0x58 _M_VEX_P_66 _M_VLEN_256 _M_MAP_0F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM() |
| OPERANDS: REG0=YMM_R():w:qq:fword64 REG1=YMM_N():r:qq:fword64 MEM0:r:qq:fword64 |
| |
| PATTERN: _M_VV_TRUE 0x58 _M_VEX_P_66 _M_VLEN_256 _M_MAP_0F MOD[0b11] MOD=3 REG[rrr] RM[nnn] |
| OPERANDS: REG0=YMM_R():w:qq:fword64 REG1=YMM_N():r:qq:fword64 REG2=YMM_B():r:qq:fword64 |
| }`) |
| |
| objects, err := xeddata.NewReader(input).ReadAll() |
| if err != nil { |
| log.Fatal(err) |
| } |
| db, err := xeddata.NewDatabase(xedPath) |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| for _, o := range objects { |
| for _, inst := range o.Insts { |
| fmt.Printf("old: %q\n", inst.Pattern) |
| fmt.Printf("new: %q\n", xeddata.ExpandStates(db, inst.Pattern)) |
| } |
| } |
| |
| //Output: |
| // old: "_M_VV_TRUE 0x58 _M_VEX_P_66 _M_VLEN_128 _M_MAP_0F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()" |
| // new: "VEXVALID=1 0x58 VEX_PREFIX=1 VL=0 MAP=1 MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()" |
| // old: "_M_VV_TRUE 0x58 _M_VEX_P_66 _M_VLEN_128 _M_MAP_0F MOD[0b11] MOD=3 REG[rrr] RM[nnn]" |
| // new: "VEXVALID=1 0x58 VEX_PREFIX=1 VL=0 MAP=1 MOD[0b11] MOD=3 REG[rrr] RM[nnn]" |
| // old: "_M_VV_TRUE 0x58 _M_VEX_P_66 _M_VLEN_256 _M_MAP_0F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()" |
| // new: "VEXVALID=1 0x58 VEX_PREFIX=1 VL=1 MAP=1 MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()" |
| // old: "_M_VV_TRUE 0x58 _M_VEX_P_66 _M_VLEN_256 _M_MAP_0F MOD[0b11] MOD=3 REG[rrr] RM[nnn]" |
| // new: "VEXVALID=1 0x58 VEX_PREFIX=1 VL=1 MAP=1 MOD[0b11] MOD=3 REG[rrr] RM[nnn]" |
| } |
| |
| // This example shows how to handle Inst "OPERANDS" field. |
| func ExampleOperand() { |
| const xedPath = "testdata/xedpath" |
| |
| input := strings.NewReader(` |
| { |
| ICLASS: ADD_N_TIMES # Like IMUL |
| CPL: 3 |
| CATEGORY: BINARY |
| EXTENSION: BASE |
| ISA_SET: I86 |
| FLAGS: MUST [ of-mod sf-u zf-u af-u pf-u cf-mod ] |
| |
| PATTERN: 0xAA MOD[mm] MOD!=3 REG[0b101] RM[nnn] MODRM() |
| OPERANDS: MEM0:r:width_v REG0=AX:rw:SUPP REG1=DX:w:SUPP |
| }`) |
| |
| objects, err := xeddata.NewReader(input).ReadAll() |
| if err != nil { |
| log.Fatal(err) |
| } |
| db, err := xeddata.NewDatabase(xedPath) |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| inst := objects[0].Insts[0] // Single instruction is enough for this example |
| for i, rawOperand := range strings.Fields(inst.Operands) { |
| operand, err := xeddata.NewOperand(db, rawOperand) |
| if err != nil { |
| log.Fatalf("parse operand #%d: %+v", i, err) |
| } |
| |
| visibility := "implicit" |
| if operand.IsVisible() { |
| visibility = "explicit" |
| } |
| fmt.Printf("(%s) %s:\n", visibility, rawOperand) |
| |
| fmt.Printf("\tname: %q\n", operand.Name) |
| if operand.IsVisible() { |
| fmt.Printf("\t32/64bit width: %s/%s bytes\n", |
| db.WidthSize(operand.Width, xeddata.OpSize32), |
| db.WidthSize(operand.Width, xeddata.OpSize64)) |
| } |
| } |
| |
| //Output: |
| // (explicit) MEM0:r:width_v: |
| // name: "MEM0" |
| // 32/64bit width: 4/8 bytes |
| // (implicit) REG0=AX:rw:SUPP: |
| // name: "REG0=AX" |
| // (implicit) REG1=DX:w:SUPP: |
| // name: "REG1=DX" |
| } |