gmbytecode/src/gmb_disassemble.erl
Craig Everett 1cdcb9150b
All checks were successful
Gajumaru Bytecode Tests / tests (push) Successful in -3m34s
Revamp (#235)
Add Gitea tests
Rename
Remove oracle references
Package for zx

Reviewed-on: #235
Reviewed-by: dimitar.p.ivanov <dimitarivanov@qpq.swiss>
Co-authored-by: Craig Everett <zxq9@zxq9.com>
Co-committed-by: Craig Everett <zxq9@zxq9.com>
2025-01-22 21:12:54 +09:00

106 lines
3.9 KiB
Erlang

%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc
%%% Prettyprint aevm machine code
%%% @end
%%% Updated : 22 Jan 2025
%%% Created : 02 Oct 2017
%%%-------------------------------------------------------------------
-module(gmb_disassemble).
-vsn("3.4.1").
-export([ pp/1,
format/2,
format_address/1
]).
-include_lib("gmbytecode/include/gmb_opcodes.hrl").
pp(Binary) ->
Listing = format(Binary, fun io:format/2),
io:format("~s~n", [Listing]).
format(Binary, ErrFormatFun) ->
pp(0, binary:bin_to_list(Binary), [], ErrFormatFun).
pp(Address, [Op|Ops], Assembly, ErrFormatFun) ->
case Op of
X when (X >= ?STOP) andalso (X =< ?SIGNEXTEND) ->
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?LT) andalso (X =< ?BYTE) ->
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?SHA3) andalso (X =< ?SHA3) ->
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?ADDRESS) andalso (X =< ?EXTCODECOPY) ->
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?BLOCKHASH) andalso (X =< ?GASLIMIT) ->
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?POP) andalso (X =< ?JUMPDEST) ->
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?PUSH1) andalso (X =< ?PUSH32) ->
Bytes = X-?PUSH1+1,
{ArgList, NextOps} = lists:split(Bytes, Ops),
Arg = arglist_to_arg(ArgList),
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), [{Arg,8*Bytes}]),
next(Address+Bytes, NextOps, Instr, Assembly, ErrFormatFun);
X when (X >= ?DUP1) andalso (X =< ?LOG4) ->
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?CREATE) andalso (X =< ?DELEGATECALL) ->
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?INVALID) andalso (X =< ?SUICIDE) ->
Instr = pp_instruction(Address, gmb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
_ ->
ErrFormatFun("unhandled op ~p at ~p",[Op, Address]),
next(Address, Ops, "", Assembly, ErrFormatFun)
end;
pp(_, [], Assembly, _) -> lists:reverse(Assembly).
arglist_to_arg([B|Bs]) ->
arglist_to_arg(Bs, B).
arglist_to_arg([B|Bs], Acc) ->
arglist_to_arg(Bs, Acc*256 + B);
arglist_to_arg([], Acc) -> Acc.
pp_instruction(Address, Op, Args) ->
[format_address(Address), " ",
pad_op(atom_to_list(Op)),
pp_args(Args),
"\n"].
format_address(Address) ->
io_lib:format("0x~8.16.0B",[Address]).
pad_op(Op) ->
N = length(Op),
Pad = 17 - N,
[Op,lists:duplicate(Pad, 32)].
pp_args([]) -> [];
pp_args([{Arg, Size}]) ->
case Size of
8 -> io_lib:format("0x~2.16.0B",[Arg]);
160 -> io_lib:format("0x~64.16.0B",[Arg]);
232 -> io_lib:format("0x~64.16.0B",[Arg]);
256 -> io_lib:format("0x~64.16.0B",[Arg]);
_ -> io_lib:format("0x~64.16.0B",[Arg])
end;
pp_args([{Arg, Size}|Args]) ->
[pp_args([{Arg, Size}]), " ", pp_args(Args)].
next(Address, Ops, Instr, Assembly, ErrFormatFun) ->
pp(Address+1, Ops, [Instr|Assembly], ErrFormatFun).