1/*
2 * gomacro - A Go interpreter with Lisp-like macros
3 *
4 * Copyright (C) 2019 Massimiliano Ghilardi
5 *
6 *     This Source Code Form is subject to the terms of the Mozilla Public
7 *     License, v. 2.0. If a copy of the MPL was not distributed with this
8 *     file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 *
11 * api.go
12 *
13 *  Created on Jan 23, 2019
14 *      Author Massimiliano Ghilardi
15 */
16
17package disasm
18
19import (
20	"testing"
21
22	"github.com/bnagy/gapstone"
23	. "github.com/cosmos72/gomacro/jit"
24	"github.com/cosmos72/gomacro/jit/asm"
25)
26
27type Engine = gapstone.Engine
28
29func NewDisasm(archId ArchId) (Engine, error) {
30	var arch uint = gapstone.CS_ARCH_X86
31	var mode uint = gapstone.CS_MODE_64
32	if archId == ARM64 {
33		arch = gapstone.CS_ARCH_ARM64
34		mode = gapstone.CS_MODE_ARM // | gapstone.CS_MODE_V8
35	}
36	engine, err := gapstone.New(
37		int(arch),
38		mode,
39	)
40	if err != nil {
41		return engine, err
42	}
43	engine.SetOption(gapstone.CS_OPT_SYNTAX, gapstone.CS_OPT_SYNTAX_ATT)
44	return engine, nil
45}
46
47func Disasm(code asm.MachineCode) ([]gapstone.Instruction, error) {
48	engine, err := NewDisasm(code.ArchId)
49	if err != nil {
50		return nil, err
51	}
52	return engine.Disasm(code.Bytes, 0x10000, 0)
53}
54
55func PrintDisasm(t *testing.T, code asm.MachineCode) {
56	insns, err := Disasm(code)
57	if err != nil {
58		t.Error(err)
59	} else {
60		archId := code.ArchId
61		t.Logf("----- %v -----", archId)
62		for _, insn := range insns {
63			Show(t, archId, insn)
64		}
65	}
66}
67
68func Show(t *testing.T, archId ArchId, insn gapstone.Instruction) {
69	var prefix string
70	bytes := insn.Bytes
71	if archId == ARM64 && len(bytes) == 4 {
72		// print high byte first
73		prefix = "0x"
74		bytes[0], bytes[1], bytes[2], bytes[3] = bytes[3], bytes[2], bytes[1], bytes[0]
75	}
76	t.Logf(" %s%x%s%s\t%s", prefix, bytes, spaces(2*len(insn.Bytes)), insn.Mnemonic, insn.OpStr)
77}
78
79func spaces(n int) string {
80	return "                "[n%16:]
81}
82