Beam Disasm
Beam Disasm
erl
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2000-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
%%=======================================================================
%% Notes:
%%
1. It does NOT work for .beam files of previous BEAM versions.
%%
2. If handling of new BEAM instructions is needed, this should be
%%
inserted at the end of function resolve_inst().
%%=======================================================================
-module(beam_disasm).
-export([file/1]). %% the main function
-export([function__code/1, format_error/1]).
-ifdef(DEBUG_DISASM).
-export([dfs/1, df/1, files/1, pp/1, pp/2]).
-endif.
-author("Kostis Sagonas").
-include("beam_opcodes.hrl").
-include("beam_disasm.hrl").
%%-----------------------------------------------------------------------type
-type
-type
-type
literals()
symbolic_tag()
disasm_tag()
disasm_term()
::
::
::
::
'none' | gb_tree().
'a' | 'f' | 'h' | 'i' | 'u' | 'x' | 'y' | 'z'.
symbolic_tag() | 'fr' | 'atom' | 'float' | 'literal'.
'nil' | {disasm_tag(), _}.
%%-----------------------------------------------------------------------define(NO_DEBUG(Str,Xs), ok).
-define(DEBUG(Str,Xs), io:format(Str,Xs)).
-define(exit(Reason), exit({?MODULE,?LINE,Reason})).
%%----------------------------------------------------------------------%% Utility functions to get/set their fields. (Uncomment and export
%% them when/if they get used in other files.)
%%----------------------------------------------------------------------%% -spec function__name(#function{}) -> atom().
%% function__name(#function{name = N}) -> N.
-1-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
-2-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
-3-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
process_chunks(F) ->
case beam_lib:chunks(F, [atoms,"Code","StrT",
indexed_imports,labeled_exports]) of
{ok,{Module,
[{atoms,AtomsList},{"Code",CodeBin},{"StrT",StrBin},
{indexed_imports,ImportsList},{labeled_exports,Exports}]}} ->
Atoms = mk_atoms(AtomsList),
LambdaBin = optional_chunk(F, "FunT"),
Lambdas = beam_disasm_lambdas(LambdaBin, Atoms),
LiteralBin = optional_chunk(F, "LitT"),
Literals = beam_disasm_literals(LiteralBin),
Code = beam_disasm_code(CodeBin, Atoms, mk_imports(ImportsList),
StrBin, Lambdas, Literals, Module),
Attributes =
case optional_chunk(F, attributes) of
none -> [];
Atts when is_list(Atts) -> Atts
end,
CompInfo =
case optional_chunk(F, "CInf") of
none -> [];
CompInfoBin when is_binary(CompInfoBin) ->
binary_to_term(CompInfoBin)
end,
#beam_file{module = Module,
labeled_exports = Exports,
attributes = Attributes,
compile_info = CompInfo,
code = Code};
Error -> Error
end.
%%----------------------------------------------------------------------%% Retrieve an optional chunk or return 'none' if the chunk doesn't exist.
%%----------------------------------------------------------------------optional_chunk(F, ChunkTag) ->
case beam_lib:chunks(F, [ChunkTag]) of
{ok,{_Module,[{ChunkTag,Chunk}]}} -> Chunk;
{error,beam_lib,{missing_chunk,_,_}} -> none
end.
%%----------------------------------------------------------------------%% Disassembles the lambda (fun) table of a BEAM file.
%%-----------------------------------------------------------------------type l_info() :: {non_neg_integer(), {_,_,_,_,_,_}}.
-spec beam_disasm_lambdas('none' | binary(), gb_tree()) -> 'none' | [l_info()].
beam_disasm_lambdas(none, _) -> none;
beam_disasm_lambdas(<<_:32,Tab/binary>>, Atoms) ->
disasm_lambdas(Tab, Atoms, 0).
disasm_lambdas(<<F:32,A:32,Lbl:32,Index:32,NumFree:32,OldUniq:32,More/binary>>,
Atoms, OldIndex) ->
Info = {lookup(F, Atoms),A,Lbl,Index,NumFree,OldUniq},
[{OldIndex,Info}|disasm_lambdas(More, Atoms, OldIndex+1)];
-4-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
%%
label entry:
%%
...
%%
<on failure, use label Li to show where things died>
%%
...
%% So the labels before each func_info should be included as well.
%% Ideally, only one such label is needed, but the BEAM compiler
%% before R8 didn't care to remove the redundant ones.
%%----------------------------------------------------------------------get_function_chunks([]) ->
?exit(empty_code_segment);
get_function_chunks(Code) ->
get_funs(labels_r(Code, [])).
labels_r([], R) -> {R, []};
labels_r([{label,_}=I|Is], R) ->
labels_r(Is, [I|R]);
labels_r([{line,_}=I|Is], R) ->
labels_r(Is, [I|R]);
labels_r(Is, R) -> {R, Is}.
get_funs({[],[]}) -> [];
get_funs({_,[]}) ->
?exit(no_func_info_in_code_segment);
get_funs({LsR0,[{func_info,[{atom,M}=AtomM,{atom,F}=AtomF,ArityArg]}|Code0]})
when is_atom(M), is_atom(F) ->
Arity = resolve_arg_unsigned(ArityArg),
{LsR,Code,RestCode} = get_fun(Code0, []),
Entry = case Code of
[{label,[{u,E}]}|_] -> E;
_ -> undefined
end,
[#function{name=F,
arity=Arity,
entry=Entry,
code=lists:reverse(LsR0, [{func_info,AtomM,AtomF,Arity}|Code])}
|get_funs({LsR,RestCode})].
get_fun([{func_info,_}|_]=Is, R0) ->
{LsR,R} = labels_r(R0, []),
{LsR,lists:reverse(R),Is};
get_fun([{int_code_end,[]}], R) ->
{[],lists:reverse(R),[]};
get_fun([I|Is], R) ->
get_fun(Is, [I|R]);
get_fun([], R) ->
?DEBUG('warning: code segment did not end with int_code_end~n',[]),
{[],lists:reverse(R),[]}.
%%----------------------------------------------------------------------%% Collects local labels -- I am not sure this is 100% what is needed.
%%----------------------------------------------------------------------local_labels(Funs) ->
lists:sort(lists:foldl(fun (F, R) ->
local_labels_1(function__code(F), R)
end, [], Funs)).
-6-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
local_labels_1(Code0, R) ->
Code1 = lists:dropwhile(fun({label,_}) -> true;
({line,_}) -> true;
({func_info,_,_,_}) -> false
end, Code0),
[{func_info,{atom,M},{atom,F},A}|Code] = Code1,
local_labels_2(Code, R, {M,F,A}).
local_labels_2([{label,[{u,L}]}|Code], R, MFA) ->
local_labels_2(Code, [{L,MFA}|R], MFA);
local_labels_2(_, R, _) -> R.
%%----------------------------------------------------------------------%% Disassembles a single BEAM instruction; most instructions are handled
%% in a generic way; indexing instructions are handled separately.
%%----------------------------------------------------------------------disasm_instr(B, Bs, Atoms, Literals) ->
{SymOp, Arity} = beam_opcodes:opname(B),
case SymOp of
select_val ->
disasm_select_inst(select_val, Bs, Atoms, Literals);
select_tuple_arity ->
disasm_select_inst(select_tuple_arity, Bs, Atoms, Literals);
_ ->
try decode_n_args(Arity, Bs, Atoms, Literals) of
{Args, RestBs} ->
?NO_DEBUG("instr ~p~n", [{SymOp, Args}]),
{{SymOp, Args}, RestBs}
catch
error:Rsn ->
?NO_DEBUG("decode_n_args(~p,~p) failed~n", [Arity, Bs]),
?exit({cannot_disasm_instr, {SymOp, Arity, Rsn}})
end
end.
%%----------------------------------------------------------------------%% Disassembles a BEAM select_* instruction used for indexing.
%%
Currently handles {select_val,3} and {select_tuple_arity,3} insts.
%%
%%
The arguments of a "select"-type instruction look as follows:
%%
<reg>, {f,FailLabel}, {list, <num cases>, [<case1> ... <caseN>]}
%%
where each case is of the form [symbol,{f,Label}].
%%----------------------------------------------------------------------disasm_select_inst(Inst, Bs, Atoms, Literals) ->
{X, Bs1} = decode_arg(Bs, Atoms, Literals),
{F, Bs2} = decode_arg(Bs1, Atoms, Literals),
{Z, Bs3} = decode_arg(Bs2, Atoms, Literals),
{U, Bs4} = decode_arg(Bs3, Atoms, Literals),
{u, Len} = U,
{List, RestBs} = decode_n_args(Len, Bs4, Atoms, Literals),
{{Inst, [X,F,{Z,U,List}]}, RestBs}.
%%----------------------------------------------------------------------%% decode_arg([Byte]) -> {Arg, [Byte]}
-7-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
%%
%% - an arg can have variable length, so we must return arg + remaining bytes
%% - decodes an argument into its 'raw' form: { Tag, Value }
%%
several types map to a single tag, so the byte code instr must then
%%
assign a type to it
%%-----------------------------------------------------------------------spec decode_arg([byte(),...]) -> {{disasm_tag(),_}, [byte()]}.
decode_arg([B|Bs]) ->
Tag = decode_tag(B band 2#111),
?NO_DEBUG('Tag = ~p, B = ~p, Bs = ~p~n', [Tag, B, Bs]),
case Tag of
z ->
decode_z_tagged(Tag, B, Bs, no_literals);
_ ->
%% all other cases are handled as if they were integers
decode_int(Tag, B, Bs)
end.
-spec decode_arg([byte(),...], gb_tree(), literals()) -> {disasm_term(), [byte()]}.
decode_arg([B|Bs0], Atoms, Literals) ->
Tag = decode_tag(B band 2#111),
?NO_DEBUG('Tag = ~p, B = ~p, Bs = ~p~n', [Tag, B, Bs]),
case Tag of
z ->
decode_z_tagged(Tag, B, Bs0, Literals);
a ->
%% atom or nil
case decode_int(Tag, B, Bs0) of
{{a,0},Bs} -> {nil,Bs};
{{a,I},Bs} -> {{atom,lookup(I, Atoms)},Bs}
end;
_ ->
%% all other cases are handled as if they were integers
decode_int(Tag, B, Bs0)
end.
%%----------------------------------------------------------------------%% Decodes an integer value. Handles positives, negatives, and bignums.
%%
%% Tries to do the opposite of:
%%
beam_asm:encode(1, 5) =
[81]
%%
beam_asm:encode(1, 1000) =
[105,232]
%%
beam_asm:encode(1, 2047) =
[233,255]
%%
beam_asm:encode(1, 2048) =
[25,8,0]
%%
beam_asm:encode(1,-1) =
[25,255,255]
%%
beam_asm:encode(1,-4294967295) =
[121,255,0,0,0,1]
%%
beam_asm:encode(1, 4294967295) =
[121,0,255,255,255,255]
%%
beam_asm:encode(1, 429496729501) = [121,99,255,255,255,157]
%%----------------------------------------------------------------------decode_int(Tag,B,Bs) when (B band 16#08) =:= 0 ->
%% N < 16 = 4 bits, NNNN:0:TTT
N = B bsr 4,
{{Tag,N},Bs};
-8-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
{{u,LitIndex},RestBs} = decode_arg(Bs),
{{literal,gb_trees:get(LitIndex, Literals)},RestBs};
_ ->
?exit({decode_z_tagged,{invalid_extended_tag,N}})
end;
decode_z_tagged(_,B,_,_) ->
?exit({decode_z_tagged,{weird_value,B}}).
-spec decode_float([byte(),...]) -> {{'float', float()}, [byte()]}.
decode_float(Bs) ->
{FL,RestBs} = take_bytes(8,Bs),
<<Float:64/float>> = list_to_binary(FL),
{{float,Float},RestBs}.
-spec decode_fr([byte(),...]) -> {{'fr', non_neg_integer()}, [byte()]}.
decode_fr(Bs) ->
{{u,Fr},RestBs} = decode_arg(Bs),
{{fr,Fr},RestBs}.
decode_alloc_list(Bs, Literals) ->
{{u,N},RestBs} = decode_arg(Bs),
decode_alloc_list_1(N, Literals, RestBs, []).
decode_alloc_list_1(0, _Literals, RestBs, Acc) ->
{{u,{alloc,lists:reverse(Acc)}},RestBs};
decode_alloc_list_1(N, Literals, Bs0, Acc) ->
{{u,Type},Bs1} = decode_arg(Bs0),
{{u,Val},Bs} = decode_arg(Bs1),
Res = case Type of
0 -> {words,Val};
1 -> {floats,Val};
2 -> {literal,gb_trees:get(Val, Literals)}
end,
decode_alloc_list_1(N-1, Literals, Bs, [Res|Acc]).
%%----------------------------------------------------------------------%% take N bytes from a stream, return {Taken_bytes, Remaining_bytes}
%%-----------------------------------------------------------------------spec take_bytes(non_neg_integer(), [byte()]) -> {[byte()], [byte()]}.
take_bytes(N, Bs) ->
take_bytes(N, Bs, []).
take_bytes(N, [B|Bs], Acc) when N > 0 ->
take_bytes(N-1, Bs, [B|Acc]);
take_bytes(0, Bs, Acc) ->
{lists:reverse(Acc), Bs}.
%%----------------------------------------------------------------------%% from a list of bytes Bn,Bn-1,...,B1,B0
%% build (Bn << 8*n) bor ... bor (B1 << 8) bor (B0 << 0)
%%----------------------------------------------------------------------build_arg(Bs) ->
-10-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
build_arg(Bs, 0).
build_arg([B|Bs], N) ->
build_arg(Bs, (N bsl 8) bor B);
build_arg([], N) ->
N.
%%----------------------------------------------------------------------%% Decodes a bunch of arguments and returns them in a list
%%----------------------------------------------------------------------decode_n_args(N, Bs, Atoms, Literals) when N >= 0 ->
decode_n_args(N, [], Bs, Atoms, Literals).
decode_n_args(N, Acc, Bs0, Atoms, Literals) when N > 0 ->
{A1,Bs} = decode_arg(Bs0, Atoms, Literals),
decode_n_args(N-1, [A1|Acc], Bs, Atoms, Literals);
decode_n_args(0, Acc, Bs, _, _) ->
{lists:reverse(Acc),Bs}.
%%----------------------------------------------------------------------%% Convert a numeric tag value into a symbolic one
%%-----------------------------------------------------------------------spec decode_tag(0..7) -> symbolic_tag().
decode_tag(?tag_u)
decode_tag(?tag_i)
decode_tag(?tag_a)
decode_tag(?tag_x)
decode_tag(?tag_y)
decode_tag(?tag_f)
decode_tag(?tag_h)
decode_tag(?tag_z)
->
->
->
->
->
->
->
->
u;
i;
a;
x;
y;
f;
h;
z.
%%----------------------------------------------------------------------%% - replace all references {a,I} with the atom with index I (or {atom,A})
%% - replace all references to {i,K} in an external call position with
%%
the proper MFA (position in list, first elt = 0, yields MFA to use)
%% - resolve strings, represented as <offset, length>, into their
%%
actual values by using string table
%%
(note: string table should be passed as a BINARY so that we can
%%
use binary_to_list/3!)
%% - convert instruction to its readable form ...
%%
%% Currently, only the first three are done (systematically, at least).
%%
%% Note: It MAY be premature to remove the lists of args, since that
%% representation means it is simpler to iterate over all args, etc.
%%----------------------------------------------------------------------resolve_names(Fun, Imports, Str, Lbls, Lambdas, Literals, M) ->
[resolve_inst(Instr, Imports, Str, Lbls, Lambdas, Literals, M) || Instr <- Fun].
%%
%% New make_fun2/4 instruction added in August 2001 (R8).
%% We handle it specially here to avoid adding an argument to
-11-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
send;
resolve_inst({remove_message,[]},_,_,_) ->
remove_message;
resolve_inst({timeout,[]},_,_,_) ->
timeout;
resolve_inst({loop_rec,[Lbl,Dst]},_,_,_) ->
{loop_rec,Lbl,Dst};
resolve_inst({loop_rec_end,[Lbl]},_,_,_) ->
{loop_rec_end,Lbl};
resolve_inst({wait,[Lbl]},_,_,_) ->
{wait,Lbl};
resolve_inst({wait_timeout,[Lbl,Int]},_,_,_) ->
{wait_timeout,Lbl,resolve_arg(Int)};
resolve_inst({m_plus,Args},_,_,_) ->
[W,SrcR1,SrcR2,DstR] = resolve_args(Args),
{arithbif,'+',W,[SrcR1,SrcR2],DstR};
resolve_inst({m_minus,Args},_,_,_) ->
[W,SrcR1,SrcR2,DstR] = resolve_args(Args),
{arithbif,'-',W,[SrcR1,SrcR2],DstR};
resolve_inst({m_times,Args},_,_,_) ->
[W,SrcR1,SrcR2,DstR] = resolve_args(Args),
{arithbif,'*',W,[SrcR1,SrcR2],DstR};
resolve_inst({m_div,Args},_,_,_) ->
[W,SrcR1,SrcR2,DstR] = resolve_args(Args),
{arithbif,'/',W,[SrcR1,SrcR2],DstR};
resolve_inst({int_div,Args},_,_,_) ->
[W,SrcR1,SrcR2,DstR] = resolve_args(Args),
{arithbif,'div',W,[SrcR1,SrcR2],DstR};
resolve_inst({int_rem,Args},_,_,_) ->
[W,SrcR1,SrcR2,DstR] = resolve_args(Args),
{arithbif,'rem',W,[SrcR1,SrcR2],DstR};
resolve_inst({int_band,Args},_,_,_) ->
[W,SrcR1,SrcR2,DstR] = resolve_args(Args),
{arithbif,'band',W,[SrcR1,SrcR2],DstR};
resolve_inst({int_bor,Args},_,_,_) ->
[W,SrcR1,SrcR2,DstR] = resolve_args(Args),
{arithbif,'bor',W,[SrcR1,SrcR2],DstR};
resolve_inst({int_bxor,Args},_,_,_) ->
[W,SrcR1,SrcR2,DstR] = resolve_args(Args),
{arithbif,'bxor',W,[SrcR1,SrcR2],DstR};
resolve_inst({int_bsl,Args},_,_,_) ->
[W,SrcR1,SrcR2,DstR] = resolve_args(Args),
{arithbif,'bsl',W,[SrcR1,SrcR2],DstR};
resolve_inst({int_bsr,Args},_,_,_) ->
[W,SrcR1,SrcR2,DstR] = resolve_args(Args),
{arithbif,'bsr',W,[SrcR1,SrcR2],DstR};
resolve_inst({int_bnot,Args},_,_,_) ->
[W,SrcR,DstR] = resolve_args(Args),
{arithbif,'bnot',W,[SrcR],DstR};
resolve_inst({is_lt=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_ge=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_eq=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
-13-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
{test,I,L,Args};
resolve_inst({is_ne=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_eq_exact=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_ne_exact=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_integer=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_float=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_number=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_atom=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_pid=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_reference=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_port=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_nil=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_binary=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_constant=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_list=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_nonempty_list=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({is_tuple=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({test_arity=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({select_val,Args},_,_,_) ->
[Reg,FLbl,{{z,1},{u,_Len},List0}] = Args,
List = resolve_args(List0),
{select_val,Reg,FLbl,{list,List}};
resolve_inst({select_tuple_arity,Args},_,_,_) ->
-14-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
[Reg,FLbl,{{z,1},{u,_Len},List0}] = Args,
List = resolve_args(List0),
{select_tuple_arity,Reg,FLbl,{list,List}};
resolve_inst({jump,[Lbl]},_,_,_) ->
{jump,Lbl};
resolve_inst({'catch',[Dst,Lbl]},_,_,_) ->
{'catch',Dst,Lbl};
resolve_inst({catch_end,[Dst]},_,_,_) ->
{catch_end,Dst};
resolve_inst({move,[Src,Dst]},_,_,_) ->
{move,resolve_arg(Src),Dst};
resolve_inst({get_list,[Src,Dst1,Dst2]},_,_,_) ->
{get_list,Src,Dst1,Dst2};
resolve_inst({get_tuple_element,[Src,{u,Off},Dst]},_,_,_) ->
{get_tuple_element,resolve_arg(Src),Off,resolve_arg(Dst)};
resolve_inst({set_tuple_element,[Src,Dst,{u,Off}]},_,_,_) ->
{set_tuple_element,resolve_arg(Src),resolve_arg(Dst),Off};
resolve_inst({put_string,[{u,Len},{u,Off},Dst]},_,Strings,_) ->
String = if Len > 0 -> binary_to_list(Strings, Off+1, Off+Len);
true -> ""
end,
{put_string,Len,{string,String},Dst};
resolve_inst({put_list,[Src1,Src2,Dst]},_,_,_) ->
{put_list,resolve_arg(Src1),resolve_arg(Src2),Dst};
resolve_inst({put_tuple,[{u,Arity},Dst]},_,_,_) ->
{put_tuple,Arity,Dst};
resolve_inst({put,[Src]},_,_,_) ->
{put,resolve_arg(Src)};
resolve_inst({badmatch,[X]},_,_,_) ->
{badmatch,resolve_arg(X)};
resolve_inst({if_end,[]},_,_,_) ->
if_end;
resolve_inst({case_end,[X]},_,_,_) ->
{case_end,resolve_arg(X)};
resolve_inst({call_fun,[{u,N}]},_,_,_) ->
{call_fun,N};
resolve_inst({make_fun,Args},_,_,Lbls) ->
[{f,L},Magic,FreeVars] = resolve_args(Args),
{make_fun,lookup(L,Lbls),Magic,FreeVars};
resolve_inst({is_function=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
resolve_inst({call_ext_only,[{u,N},{u,MFAix}]},Imports,_,_) ->
{call_ext_only,N,lookup(MFAix+1,Imports)};
%%
%% Instructions for handling binaries added in R7A & R7B
%%
resolve_inst({bs_start_match,[F,Reg]},_,_,_) ->
{bs_start_match,F,Reg};
resolve_inst({bs_get_integer=I,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
[A2,A5] = resolve_args([Arg2,Arg5]),
{test,I,Lbl,[A2,N,decode_field_flags(U),A5]};
resolve_inst({bs_get_float=I,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
[A2,A5] = resolve_args([Arg2,Arg5]),
{test,I,Lbl,[A2,N,decode_field_flags(U),A5]};
resolve_inst({bs_get_binary=I,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
[A2,A5] = resolve_args([Arg2,Arg5]),
-15-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
{test,I,Lbl,[A2,N,decode_field_flags(U),A5]};
resolve_inst({bs_skip_bits,[Lbl,Arg2,{u,N},{u,U}]},_,_,_) ->
A2 = resolve_arg(Arg2),
{test,bs_skip_bits,Lbl,[A2,N,decode_field_flags(U)]};
resolve_inst({bs_test_tail,[F,{u,N}]},_,_,_) ->
{test,bs_test_tail,F,[N]};
resolve_inst({bs_save,[{u,N}]},_,_,_) ->
{bs_save,N};
resolve_inst({bs_restore,[{u,N}]},_,_,_) ->
{bs_restore,N};
resolve_inst({bs_init,[{u,N},{u,U}]},_,_,_) ->
{bs_init,N,decode_field_flags(U)};
resolve_inst({bs_final,[F,X]},_,_,_) ->
{bs_final,F,X};
resolve_inst({bs_put_integer,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
[A2,A5] = resolve_args([Arg2,Arg5]),
{bs_put_integer,Lbl,A2,N,decode_field_flags(U),A5};
resolve_inst({bs_put_binary,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
[A2,A5] = resolve_args([Arg2,Arg5]),
{bs_put_binary,Lbl,A2,N,decode_field_flags(U),A5};
resolve_inst({bs_put_float,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
[A2,A5] = resolve_args([Arg2,Arg5]),
{bs_put_float,Lbl,A2,N,decode_field_flags(U),A5};
resolve_inst({bs_put_string,[{u,Len},{u,Off}]},_,Strings,_) ->
String = if Len > 0 -> binary_to_list(Strings, Off+1, Off+Len);
true -> ""
end,
{bs_put_string,Len,{string,String}};
resolve_inst({bs_need_buf,[{u,N}]},_,_,_) ->
{bs_need_buf,N};
%%
%% Instructions for handling floating point numbers added in June 2001 (R8).
%%
resolve_inst({fclearerror,[]},_,_,_) ->
fclearerror;
resolve_inst({fcheckerror,[Arg]},_,_,_) ->
{fcheckerror,resolve_arg(Arg)};
resolve_inst({fmove,Args},_,_,_) ->
[FR,Reg] = resolve_args(Args),
{fmove,FR,Reg};
resolve_inst({fconv,Args},_,_,_) ->
[Reg,FR] = resolve_args(Args),
{fconv,Reg,FR};
resolve_inst({fadd=I,Args},_,_,_) ->
[F,A1,A2,Reg] = resolve_args(Args),
{arithfbif,I,F,[A1,A2],Reg};
resolve_inst({fsub=I,Args},_,_,_) ->
[F,A1,A2,Reg] = resolve_args(Args),
{arithfbif,I,F,[A1,A2],Reg};
resolve_inst({fmul=I,Args},_,_,_) ->
[F,A1,A2,Reg] = resolve_args(Args),
{arithfbif,I,F,[A1,A2],Reg};
resolve_inst({fdiv=I,Args},_,_,_) ->
[F,A1,A2,Reg] = resolve_args(Args),
{arithfbif,I,F,[A1,A2],Reg};
resolve_inst({fnegate,Args},_,_,_) ->
-16-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
[F,Arg,Reg] = resolve_args(Args),
{arithfbif,fnegate,F,[Arg],Reg};
%%
%% Instructions for try expressions added in January 2003 (R10).
%%
resolve_inst({'try',[Reg,Lbl]},_,_,_) -> % analogous to 'catch'
{'try',Reg,Lbl};
resolve_inst({try_end,[Reg]},_,_,_) ->
% analogous to 'catch_end'
{try_end,Reg};
resolve_inst({try_case,[Reg]},_,_,_) -> % analogous to 'catch_end'
{try_case,Reg};
resolve_inst({try_case_end,[Arg]},_,_,_) ->
{try_case_end,resolve_arg(Arg)};
resolve_inst({raise,[_Reg1,_Reg2]=Regs},_,_,_) ->
{raise,{f,0},Regs,{x,0}};
% do NOT wrap this as a 'bif'
% as there is no raise/2 bif!
%%
%% New bit syntax instructions added in February 2004 (R10B).
%%
resolve_inst({bs_init2,[Lbl,Arg2,{u,W},{u,R},{u,F},Arg6]},_,_,_) ->
[A2,A6] = resolve_args([Arg2,Arg6]),
{bs_init2,Lbl,A2,W,R,decode_field_flags(F),A6};
resolve_inst({bs_bits_to_bytes,[Lbl,Arg2,Arg3]},_,_,_) ->
[A2,A3] = resolve_args([Arg2,Arg3]),
{bs_bits_to_bytes,Lbl,A2,A3};
resolve_inst({bs_add=I,[Lbl,Arg2,Arg3,Arg4,Arg5]},_,_,_) ->
[A2,A3,A4,A5] = resolve_args([Arg2,Arg3,Arg4,Arg5]),
{I,Lbl,[A2,A3,A4],A5};
%%
%% New apply instructions added in April 2004 (R10B).
%%
resolve_inst({apply,[{u,Arity}]},_,_,_) ->
{apply,Arity};
resolve_inst({apply_last,[{u,Arity},{u,D}]},_,_,_) ->
{apply_last,Arity,D};
%%
%% New test instruction added in April 2004 (R10B).
%%
resolve_inst({is_boolean=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
%%
%% New instruction added in June 2005.
%%
resolve_inst({is_function2=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
%%
%% New bit syntax matching added in Dec 2005 (R11B).
%%
resolve_inst({bs_start_match2=I,[F,Reg,{u,Live},{u,Max},Ms]},_,_,_) ->
-17-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
{test,I,F,[Reg,Live,Max,Ms]};
resolve_inst({bs_get_integer2=I,[Lbl,Ms,{u,Live},Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
[A2,A5] = resolve_args([Arg2,Arg5]),
{test,I,Lbl,[Ms, Live,A2,N,decode_field_flags(U),A5]};
resolve_inst({bs_get_binary2=I,[Lbl,Ms,{u,Live},Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
[A2,A5] = resolve_args([Arg2,Arg5]),
{test,I,Lbl,[Ms, Live,A2,N,decode_field_flags(U),A5]};
resolve_inst({bs_get_float2=I,[Lbl,Ms,{u,Live},Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
[A2,A5] = resolve_args([Arg2,Arg5]),
{test,I,Lbl,[Ms, Live,A2,N,decode_field_flags(U),A5]};
resolve_inst({bs_skip_bits2=I,[Lbl,Ms,Arg2,{u,N},{u,U}]},_,_,_) ->
A2 = resolve_arg(Arg2),
{test,I,Lbl,[Ms,A2,N,decode_field_flags(U)]};
resolve_inst({bs_test_tail2=I,[F,Ms,{u,N}]},_,_,_) ->
{test,I,F,[Ms,N]};
resolve_inst({bs_save2=I,[Ms,{u,N}]},_,_,_) ->
{I,Ms,N};
resolve_inst({bs_restore2=I,[Ms,{u,N}]},_,_,_) ->
{I,Ms,N};
resolve_inst({bs_save2=I,[Ms,{atom,_}=Atom]},_,_,_) ->
%% New operand type in R12B.
{I,Ms,Atom};
resolve_inst({bs_restore2=I,[Ms,{atom,_}=Atom]},_,_,_) ->
%% New operand type in R12B.
{I,Ms,Atom};
%%
%% New instructions for guard BIFs that may GC. Added in Jan 2006 (R11B).
%%
resolve_inst({gc_bif1,Args},Imports,_,_) ->
[F,Live,Bif,A1,Reg] = resolve_args(Args),
{extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports),
{gc_bif,BifName,F,Live,[A1],Reg};
resolve_inst({gc_bif2,Args},Imports,_,_) ->
[F,Live,Bif,A1,A2,Reg] = resolve_args(Args),
{extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports),
{gc_bif,BifName,F,Live,[A1,A2],Reg};
%%
%% New instruction in R14, gc_bif with 3 arguments
%%
resolve_inst({gc_bif3,Args},Imports,_,_) ->
[F,Live,Bif,A1,A2,A3,Reg] = resolve_args(Args),
{extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports),
{gc_bif,BifName,F,Live,[A1,A2,A3],Reg};
%%
%% New instructions for creating non-byte aligned binaries.
%%
resolve_inst({bs_final2,[X,Y]},_,_,_) ->
{bs_final2,X,Y};
%%
%% R11B-5.
%%
resolve_inst({is_bitstr=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
-18-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
%%
%% R12B.
%%
resolve_inst({bs_context_to_binary=I,[Reg0]},_,_,_) ->
Reg = resolve_arg(Reg0),
{I,Reg};
resolve_inst({bs_test_unit=I,[F,Ms,{u,N}]},_,_,_) ->
{test,I,F,[Ms,N]};
resolve_inst({bs_match_string=I,[F,Ms,{u,Bits},{u,Off}]},_,Strings,_) ->
Len = (Bits+7) div 8,
String = if
Len > 0 ->
<<_:Off/binary,Bin:Len/binary,_/binary>> = Strings,
Bin;
true -> <<>>
end,
{test,I,F,[Ms,Bits,String]};
resolve_inst({bs_init_writable=I,[]},_,_,_) ->
I;
resolve_inst({bs_append=I,[Lbl,Arg2,{u,W},{u,R},{u,U},Arg6,{u,F},Arg8]},_,_,_) ->
[A2,A6,A8] = resolve_args([Arg2,Arg6,Arg8]),
{I,Lbl,A2,W,R,U,A6,decode_field_flags(F),A8};
resolve_inst({bs_private_append=I,[Lbl,Arg2,{u,U},Arg4,{u,F},Arg6]},_,_,_) ->
[A2,A4,A6] = resolve_args([Arg2,Arg4,Arg6]),
{I,Lbl,A2,U,A4,decode_field_flags(F),A6};
resolve_inst({trim=I,[{u,N},{u,Remaining}]},_,_,_) ->
{I,N,Remaining};
resolve_inst({bs_init_bits,[Lbl,Arg2,{u,W},{u,R},{u,F},Arg6]},_,_,_) ->
[A2,A6] = resolve_args([Arg2,Arg6]),
{bs_init_bits,Lbl,A2,W,R,decode_field_flags(F),A6};
%%
%% R12B-5.
%%
resolve_inst({bs_get_utf8=I,[Lbl,Arg2,Arg3,{u,U},Arg4]},_,_,_) ->
[A2,A3,A4] = resolve_args([Arg2,Arg3,Arg4]),
{test,I,Lbl,[A2,A3,decode_field_flags(U),A4]};
resolve_inst({bs_skip_utf8=I,[Lbl,Arg2,Arg3,{u,U}]},_,_,_) ->
[A2,A3] = resolve_args([Arg2,Arg3]),
{test,I,Lbl,[A2,A3,decode_field_flags(U)]};
resolve_inst({bs_get_utf16=I,[Lbl,Arg2,Arg3,{u,U},Arg4]},_,_,_) ->
[A2,A3,A4] = resolve_args([Arg2,Arg3,Arg4]),
{test,I,Lbl,[A2,A3,decode_field_flags(U),A4]};
resolve_inst({bs_skip_utf16=I,[Lbl,Arg2,Arg3,{u,U}]},_,_,_) ->
[A2,A3] = resolve_args([Arg2,Arg3]),
{test,I,Lbl,[A2,A3,decode_field_flags(U)]};
resolve_inst({bs_get_utf32=I,[Lbl,Arg2,Arg3,{u,U},Arg4]},_,_,_) ->
[A2,A3,A4] = resolve_args([Arg2,Arg3,Arg4]),
{test,I,Lbl,[A2,A3,decode_field_flags(U),A4]};
resolve_inst({bs_skip_utf32=I,[Lbl,Arg2,Arg3,{u,U}]},_,_,_) ->
[A2,A3] = resolve_args([Arg2,Arg3]),
{test,I,Lbl,[A2,A3,decode_field_flags(U)]};
resolve_inst({bs_utf8_size=I,[Lbl,Arg2,Arg3]},_,_,_) ->
[A2,A3] = resolve_args([Arg2,Arg3]),
{I,Lbl,A2,A3};
resolve_inst({bs_put_utf8=I,[Lbl,{u,U},Arg3]},_,_,_) ->
-19-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
A3 = resolve_arg(Arg3),
{I,Lbl,decode_field_flags(U),A3};
resolve_inst({bs_utf16_size=I,[Lbl,Arg2,Arg3]},_,_,_) ->
[A2,A3] = resolve_args([Arg2,Arg3]),
{I,Lbl,A2,A3};
resolve_inst({bs_put_utf16=I,[Lbl,{u,U},Arg3]},_,_,_) ->
A3 = resolve_arg(Arg3),
{I,Lbl,decode_field_flags(U),A3};
resolve_inst({bs_put_utf32=I,[Lbl,{u,U},Arg3]},_,_,_) ->
A3 = resolve_arg(Arg3),
{I,Lbl,decode_field_flags(U),A3};
%%
%% R13B03.
%%
resolve_inst({on_load,[]},_,_,_) ->
on_load;
%%
%% R14A.
%%
resolve_inst({recv_mark,[Lbl]},_,_,_) ->
{recv_mark,Lbl};
resolve_inst({recv_set,[Lbl]},_,_,_) ->
{recv_set,Lbl};
%%
%% R15A.
%%
resolve_inst({line,[Index]},_,_,_) ->
{line,resolve_arg(Index)};
%%
%% Catches instructions that are not yet handled.
%%
resolve_inst(X,_,_,_) -> ?exit({resolve_inst,X}).
%%----------------------------------------------------------------------%% Resolves arguments in a generic way.
%%----------------------------------------------------------------------resolve_args(Args) -> [resolve_arg(A) || A <- Args].
resolve_arg({x,N} = Arg) when is_integer(N), N >= 0 -> Arg;
resolve_arg({y,N} = Arg) when is_integer(N), N >= 0 -> Arg;
resolve_arg({fr,N} = Arg) when is_integer(N), N >= 0 -> Arg;
resolve_arg({f,N} = Arg) when is_integer(N), N >= 0 -> Arg;
resolve_arg({u,_} = Arg) -> resolve_arg_unsigned(Arg);
resolve_arg({i,_} = Arg) -> resolve_arg_integer(Arg);
resolve_arg({atom,Atom} = Arg) when is_atom(Atom) -> Arg;
resolve_arg({float,F} = Arg) when is_float(F) -> Arg;
resolve_arg({literal,_} = Arg) -> Arg;
resolve_arg(nil) -> nil.
resolve_arg_unsigned({u,N}) when is_integer(N), N >= 0 -> N.
resolve_arg_integer({i,N}) when is_integer(N) -> {integer,N}.
-20-
\\10.1.53.142\backup\Aurel2012\erl\lib\compiler-4.8.1\src\beam_disasm.erl
%%----------------------------------------------------------------------%% The purpose of the following is just to add a hook for future changes.
%% Currently, field flags are numbers 1-2-4-8 and only two of these
%% numbers (BSF_LITTLE 2 -- BSF_SIGNED 4) have a semantic significance;
%% others are just hints for speeding up the execution; see "erl_bits.h".
%%----------------------------------------------------------------------decode_field_flags(FF) ->
{field_flags,FF}.
%%----------------------------------------------------------------------%% Private Utilities
%%----------------------------------------------------------------------mk_imports(ImportList) ->
gb_trees:from_orddict([{I,{extfunc,M,F,A}} || {I,M,F,A} <- ImportList]).
mk_atoms(AtomList) ->
gb_trees:from_orddict(AtomList).
mk_labels(LabelList) ->
gb_trees:from_orddict(LabelList).
lookup(I, Imports) ->
gb_trees:get(I, Imports).
-21-