diff options
Diffstat (limited to 'lib/compiler/src/beam_disasm.erl')
-rw-r--r-- | lib/compiler/src/beam_disasm.erl | 200 |
1 files changed, 160 insertions, 40 deletions
diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl index 6b41c15970..35ba0ba82d 100644 --- a/lib/compiler/src/beam_disasm.erl +++ b/lib/compiler/src/beam_disasm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2022. All Rights Reserved. +%% Copyright Ericsson AB 2000-2023. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -262,19 +262,29 @@ disasm_literals(<<>>, _) -> []. %% Disassembles the type table of a BEAM file. %%----------------------------------------------------------------------- --spec beam_disasm_types('none' | binary()) -> literals(). +-spec beam_disasm_types('none' | binary()) -> types(). beam_disasm_types(none) -> none; -beam_disasm_types(<<?BEAM_TYPES_VERSION:32,Count:32,Table/binary>>) -> - Res = gb_trees:from_orddict(disasm_types(Table, 0)), - Count = gb_trees:size(Res), %Assertion. - Res. - -disasm_types(<<Type:18/binary,Rest/binary>>, Index) -> - [{Index,beam_types:decode_ext(Type)}|disasm_types(Rest, Index+1)]; -disasm_types(<<>>, _) -> - []. +beam_disasm_types(<<Version:32,Count:32,Table0/binary>>) -> + case beam_types:convert_ext(Version, Table0) of + none -> + ?exit({beam_disasm_types,{unknown_type_version,Version}}); + Table -> + Res = gb_trees:from_orddict(disasm_types(Table, 0)), + Count = gb_trees:size(Res), %Assertion. + Res + end; +beam_disasm_types(<<_/binary>>) -> + none. + +disasm_types(Types0, Index) -> + case beam_types:decode_ext(Types0) of + done -> + []; + {Types,Rest} -> + [{Index,Types}|disasm_types(Rest, Index+1)] + end. %%----------------------------------------------------------------------- %% Disassembles the code chunk of a BEAM file: @@ -412,6 +422,10 @@ disasm_instr(B, Bs, Atoms, Literals, Types) -> disasm_init_yregs(Bs, Atoms, Literals, Types); bs_create_bin -> disasm_bs_create_bin(Bs, Atoms, Literals, Types); + bs_match -> + disasm_bs_match(Bs, Atoms, Literals, Types); + update_record -> + disasm_update_record(Bs, Atoms, Literals, Types); _ -> try decode_n_args(Arity, Bs, Atoms, Literals, Types) of {Args, RestBs} -> @@ -488,6 +502,27 @@ disasm_bs_create_bin(Bs0, Atoms, Literals, Types) -> {List, RestBs} = decode_n_args(Len, Bs7, Atoms, Literals, Types), {{bs_create_bin, [{A1,A2,A3,A4,A5,Z,U,List}]}, RestBs}. +disasm_bs_match(Bs0, Atoms, Literals, Types) -> + {A1, Bs1} = decode_arg(Bs0, Atoms, Literals, Types), + {A2, Bs2} = decode_arg(Bs1, Atoms, Literals, Types), + Bs5 = Bs2, + {Z, Bs6} = decode_arg(Bs5, Atoms, Literals, Types), + {U, Bs7} = decode_arg(Bs6, Atoms, Literals, Types), + {u, Len} = U, + {List, RestBs} = decode_n_args(Len, Bs7, Atoms, Literals, Types), + {{bs_match, [{A1,A2,Z,U,List}]}, RestBs}. + +disasm_update_record(Bs1, Atoms, Literals, Types) -> + {Hint, Bs2} = decode_arg(Bs1, Atoms, Literals, Types), + {Size, Bs3} = decode_arg(Bs2, Atoms, Literals, Types), + {Src, Bs4} = decode_arg(Bs3, Atoms, Literals, Types), + {Dst, Bs6} = decode_arg(Bs4, Atoms, Literals, Types), + {Z, Bs7} = decode_arg(Bs6, Atoms, Literals, Types), + {U, Bs8} = decode_arg(Bs7, Atoms, Literals, Types), + {u, Len} = U, + {List, RestBs} = decode_n_args(Len, Bs8, Atoms, Literals, Types), + {{update_record, [Hint,Size,Src,Dst,{{Z,U,List}}]}, RestBs}. + %%----------------------------------------------------------------------- %% decode_arg([Byte]) -> {Arg, [Byte]} %% @@ -731,10 +766,14 @@ 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 +%% Instructions that need to look up an entry in the Lambda table. +%% We handle these specially here to avoid adding an argument to %% the clause for every instruction. %% +%% - make_fun2/4 (R8, added in August 2001) +%% - make_fun3/3 (OTP 24) +%% - call_fun2/3 (OTP 25) +%% resolve_inst({make_fun2,Args}, _, _, _, Lambdas, _, M) -> [OldIndex] = resolve_args(Args), @@ -747,6 +786,17 @@ resolve_inst({make_fun3,[Fun,Dst,{{z,1},{u,_},Env0}]}, _, _, _, Lambdas, _, M) - {OldIndex,{F,A,_Lbl,_Index,_NumFree,OldUniq}} = lists:keyfind(OldIndex, 1, Lambdas), {make_fun3,{M,F,A},OldIndex,OldUniq,Dst,{list,Env1}}; +resolve_inst({call_fun2,Args}, _, _, _, Lambdas, _, _) -> + [Tag0,Arity,Func] = resolve_args(Args), + Tag = case Tag0 of + Index when is_integer(Index) -> + {Tag0,{_F,_A,Label,_Index,_NumFree,_OldUniq}} = + lists:keyfind(Tag0, 1, Lambdas), + {f,Label}; + _ -> + Tag0 + end, + {call_fun2,Tag,Arity,Func}; resolve_inst(Instr, Imports, Str, Lbls, _Lambdas, _Literals, _M) -> %% io:format(?MODULE_STRING":resolve_inst ~p.~n", [Instr]), resolve_inst(Instr, Imports, Str, Lbls). @@ -943,19 +993,19 @@ resolve_inst({fconv,Args},_,_,_) -> {fconv,Reg,FR}; resolve_inst({fadd=I,Args},_,_,_) -> [F,A1,A2,Reg] = resolve_args(Args), - {arithfbif,I,F,[A1,A2],Reg}; + {bif,I,F,[A1,A2],Reg}; resolve_inst({fsub=I,Args},_,_,_) -> [F,A1,A2,Reg] = resolve_args(Args), - {arithfbif,I,F,[A1,A2],Reg}; + {bif,I,F,[A1,A2],Reg}; resolve_inst({fmul=I,Args},_,_,_) -> [F,A1,A2,Reg] = resolve_args(Args), - {arithfbif,I,F,[A1,A2],Reg}; + {bif,I,F,[A1,A2],Reg}; resolve_inst({fdiv=I,Args},_,_,_) -> [F,A1,A2,Reg] = resolve_args(Args), - {arithfbif,I,F,[A1,A2],Reg}; + {bif,I,F,[A1,A2],Reg}; resolve_inst({fnegate,Args},_,_,_) -> [F,Arg,Reg] = resolve_args(Args), - {arithfbif,fnegate,F,[Arg],Reg}; + {bif,fnegate,F,[Arg],Reg}; %% %% Instructions for try expressions added in January 2003 (R10). @@ -969,8 +1019,7 @@ resolve_inst({try_case,[Reg]},_,_,_) -> % analogous to 'catch_end' 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! + {bif,raise,{f,0},Regs,{x,0}}; %% %% New bit syntax instructions added in February 2004 (R10B). @@ -1009,15 +1058,15 @@ resolve_inst({is_function2=I,Args0},_,_,_) -> %% resolve_inst({bs_start_match2=I,[F,Reg,{u,Live},{u,Max},Ms]},_,_,_) -> {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_get_integer2=I,[Fail,Ms,{u,Live},Size0,{u,Unit},{u,Flags},Dst0]},_,_,_) -> + [Size,Dst] = resolve_args([Size0,Dst0]), + {test,I,Fail,Live,[Ms,Size,Unit,decode_field_flags(Flags)],Dst}; +resolve_inst({bs_get_binary2=I,[Fail,Ms,{u,Live},Size0,{u,Unit},{u,Flags},Dst0]},_,_,_) -> + [Size,Dst] = resolve_args([Size0,Dst0]), + {test,I,Fail,Live,[Ms,Size,Unit,decode_field_flags(Flags)],Dst}; +resolve_inst({bs_get_float2=I,[Fail,Ms,{u,Live},Size0,{u,Unit},{u,Flags},Dst0]},_,_,_) -> + [Size,Dst] = resolve_args([Size0,Dst0]), + {test,I,Fail,Live,[Ms,Size,Unit,decode_field_flags(Flags)],Dst}; 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)]}; @@ -1077,7 +1126,7 @@ resolve_inst({bs_match_string=I,[F,Ms,{u,Bits},{u,Off}]},_,Strings,_) -> Bin; true -> <<>> end, - {test,I,F,[Ms,Bits,String]}; + {test,I,F,[Ms,Bits,{string,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]},_,_,_) -> @@ -1192,11 +1241,11 @@ resolve_inst({get_tl,[Src,Dst]},_,_,_) -> resolve_inst({put_tuple2,[Dst,{{z,1},{u,_},List0}]},_,_,_) -> List = resolve_args(List0), {put_tuple2,Dst,{list,List}}; -resolve_inst({bs_start_match3,[Fail,Bin,Live,Dst]},_,_,_) -> - {bs_start_match3,Fail,Bin,Live,Dst}; -resolve_inst({bs_get_tail,[Src,Dst,Live]},_,_,_) -> +resolve_inst({bs_start_match3=I,[Fail,Bin,{u,Live},Dst]},_,_,_) -> + {test,I,Fail,Live,[Bin],Dst}; +resolve_inst({bs_get_tail,[Src,Dst,{u,Live}]},_,_,_) -> {bs_get_tail,Src,Dst,Live}; -resolve_inst({bs_get_position,[Src,Dst,Live]},_,_,_) -> +resolve_inst({bs_get_position,[Src,Dst,{u,Live}]},_,_,_) -> {bs_get_position,Src,Dst,Live}; resolve_inst({bs_set_position,[Src,Dst]},_,_,_) -> {bs_set_position,Src,Dst}; @@ -1205,7 +1254,7 @@ resolve_inst({bs_set_position,[Src,Dst]},_,_,_) -> %% OTP 23. %% -resolve_inst({bs_start_match4,[Fail,Live,Src,Dst]},_,_,_) -> +resolve_inst({bs_start_match4,[Fail,{u,Live},Src,Dst]},_,_,_) -> {bs_start_match4,Fail,Live,Src,Dst}; resolve_inst({swap,[_,_]=List},_,_,_) -> [R1,R2] = resolve_args(List), @@ -1231,16 +1280,30 @@ resolve_inst({recv_marker_use,[Reg]},_,_,_) -> %% OTP 25. %% -resolve_inst({bs_create_bin,Args},_,_,_) -> - {bs_create_bin,Args}; -resolve_inst({call_fun2,[Tag,{u,Arity},Func]},_,_,_) -> - {call_fun2,Tag,Arity,Func}; +resolve_inst({bs_create_bin, + [{Fail,{u,Heap},{u,Live},{u,Unit},Dst,{z,1},{u,_},List0}]}, + _, Strings, _) -> + List = resolve_bs_create_bin_list(List0, Strings), + {bs_create_bin,Fail,Heap,Live,Unit,Dst,{list,List}}; resolve_inst({nif_start,[]},_,_,_) -> nif_start; resolve_inst({badrecord,[Arg]},_,_,_) -> {badrecord,resolve_arg(Arg)}; %% +%% OTP 26. +%% + +resolve_inst({update_record, + [Hint,{u,Size},Src,Dst,{{{z,1},{u,_},List0}}]},_,_,_) -> + List = resolve_args(List0), + {update_record,Hint,Size,Src,Dst,{list,List}}; +resolve_inst({bs_match,[{Fail,Ctx,{z,1},{u,_},Args}]},_,_,_) -> + List = resolve_args(Args), + Commands = resolve_bs_match_commands(List), + {bs_match,Fail,Ctx,{commands,Commands}}; + +%% %% Catches instructions that are not yet handled. %% resolve_inst(X,_,_,_) -> ?exit({resolve_inst,X}). @@ -1268,13 +1331,70 @@ resolve_arg_unsigned({u,N}) when is_integer(N), N >= 0 -> N. resolve_arg_integer({i,N}) when is_integer(N) -> {integer,N}. %%----------------------------------------------------------------------- +%% Resolves the OpList for the bs_create_bin/6 instruction +%%----------------------------------------------------------------------- + +resolve_bs_create_bin_list( + [{atom,string}=Type,Seg0,Unit0,Flags,Offset0,Size0|Rest], Strings) -> + [Seg,Unit,Offset,{integer,Len}=Size] = + resolve_args([Seg0,Unit0,Offset0,Size0]), + <<_:Offset/binary,Bin:Len/binary,_/binary>> = Strings, + [Type,Seg,Unit,Flags,{string,Bin},Size | + resolve_bs_create_bin_list(Rest, Strings)]; +resolve_bs_create_bin_list([Type,Seg0,Unit0,Flags,Val0,Size0|Rest], Strings) -> + [Seg,Unit,Val,Size] = resolve_args([Seg0,Unit0,Val0,Size0]), + [Type,Seg,Unit,Flags,Val,Size | + resolve_bs_create_bin_list(Rest, Strings)]; +resolve_bs_create_bin_list([], _Str) -> + []. + +%%----------------------------------------------------------------------- +%% Resolves the Commands list for the bs_match/3 instruction +%%----------------------------------------------------------------------- + +resolve_bs_match_commands([{atom,ensure_at_least},Size,Unit|Rest]) -> + [{ensure_at_least,Size,Unit} | resolve_bs_match_commands(Rest)]; +resolve_bs_match_commands([{atom,ensure_exactly},Stride|Rest]) -> + [{ensure_exactly,Stride} | resolve_bs_match_commands(Rest)]; +resolve_bs_match_commands([{atom,integer},Live,Flags0,Size,Unit,Dst|Rest]) -> + Flags = resolve_bs_match_flags(Flags0), + [{integer,Live,Flags,Size,Unit,Dst} | + resolve_bs_match_commands(Rest)]; +resolve_bs_match_commands([{atom,binary},Live,Flags0,Size,Unit,Dst|Rest]) -> + Flags = resolve_bs_match_flags(Flags0), + [{binary,Live,Flags,Size,Unit,Dst} | + resolve_bs_match_commands(Rest)]; +resolve_bs_match_commands([{atom,'=:='},nil,Bits,Value|Rest]) -> + [{'=:=',nil,Bits,Value} | resolve_bs_match_commands(Rest)]; +resolve_bs_match_commands([{atom,skip},Stride|Rest]) -> + [{skip,Stride} | resolve_bs_match_commands(Rest)]; +resolve_bs_match_commands([{atom,get_tail},Live,Src,Dst|Rest]) -> + [{get_tail,Live,Src,Dst} | resolve_bs_match_commands(Rest)]; +resolve_bs_match_commands([]) -> + []. + +resolve_bs_match_flags(nil) -> {literal,[]}; +resolve_bs_match_flags({literal,[_|_]}=Flags) -> Flags. + +%%----------------------------------------------------------------------- %% 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". +%% Decodes field flags within bitstrings such as `Var/signed' or +%% `Var/little'. This is the opposite of `beam_asm:flag_to_bit/1'. +%% Also see "erl_bits.h". %%----------------------------------------------------------------------- -decode_field_flags(FF) -> +decode_field_flags(0) -> + {field_flags,[]}; +decode_field_flags(FieldFlags) when is_integer(FieldFlags) -> + FF = lists:filter( + fun + (little) -> (FieldFlags band 16#02) == 16#02; + (signed) -> (FieldFlags band 16#04) == 16#04; + (native) -> (FieldFlags band 16#10) == 16#10 + end, [little, signed, native]), {field_flags,FF}. %%----------------------------------------------------------------------- |