1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2000-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%%======================================================================= 20%% Notes: 21%% 1. It does NOT work for .beam files of previous BEAM versions. 22%% 2. If handling of new BEAM instructions is needed, this should be 23%% inserted at the end of function resolve_inst(). 24%%======================================================================= 25 26-module(beam_disasm). 27 28-export([file/1]). %% the main function 29-export([function__code/1, format_error/1]). 30-ifdef(DEBUG_DISASM). 31-export([dfs/1, df/1, files/1, pp/1, pp/2]). 32-endif. 33 34-author("Kostis Sagonas"). 35 36-include("beam_opcodes.hrl"). 37-include("beam_disasm.hrl"). 38 39%%----------------------------------------------------------------------- 40 41-type index() :: non_neg_integer(). 42-type literals() :: 'none' | gb_trees:tree(index(), term()). 43-type symbolic_tag() :: 'a' | 'f' | 'h' | 'i' | 'u' | 'x' | 'y' | 'z'. 44-type disasm_tag() :: symbolic_tag() | 'fr' | 'atom' | 'float' | 'literal'. 45-type disasm_term() :: 'nil' | {disasm_tag(), _}. 46 47%%----------------------------------------------------------------------- 48 49-define(NO_DEBUG(Str,Xs), ok). 50-define(DEBUG(Str,Xs), io:format(Str,Xs)). 51-define(exit(Reason), exit({?MODULE,?LINE,Reason})). 52 53%%----------------------------------------------------------------------- 54%% Utility functions to get/set their fields. (Uncomment and export 55%% them when/if they get used in other files.) 56%%----------------------------------------------------------------------- 57 58%% -spec function__name(#function{}) -> atom(). 59%% function__name(#function{name = N}) -> N. 60%% -spec function__arity(#function{}) -> arity(). 61%% function__arity(#function{arity = A}) -> A. 62%% function__entry(#function{entry = E}) -> E. 63 64-spec function__code(#function{}) -> [beam_instr()]. 65function__code(#function{code = Code}) -> Code. 66 67-spec function__code_update(#function{}, [beam_instr()]) -> #function{}. 68function__code_update(Function, NewCode) -> 69 Function#function{code = NewCode}. 70 71%%----------------------------------------------------------------------- 72%% Error information 73 74-spec format_error({'internal',term()} | {'error',atom(),term()}) -> string(). 75 76format_error({internal,Error}) -> 77 io_lib:format("~p: disassembly failed with reason ~P.", 78 [?MODULE, Error, 25]); 79format_error({error,Module,Error}) -> 80 lists:flatten(Module:format_error(Error)). 81 82%%----------------------------------------------------------------------- 83%% User comfort functions to directly disassemble to file or to 84%% stream, pretty-printed, and to just pretty-print, also commented. 85%%----------------------------------------------------------------------- 86 87-ifdef(DEBUG_DISASM). 88 89dfs(Files) when is_list(Files) -> 90 lists:foreach(fun df/1, Files). 91 92df(Module) when is_atom(Module) -> 93 case code:which(Module) of 94 File when is_list(File) -> 95 df(File); 96 Reason when is_atom(Reason) -> 97 {error,?MODULE,Reason} 98 end; 99df(File) when is_list(File) -> 100 file(File, filename:rootname(File, ".beam")++".dis"). 101 102files(Files) when is_list(Files) -> 103 lists:foreach(fun (File) -> file(File, group_leader()) end, Files). 104 105file(File, Dest) -> 106 case file(File) of 107 #beam_file{code = DisasmCode} -> 108 pp(Dest, [{file,File}, {code,DisasmCode}]); 109 Error -> Error 110 end. 111 112-spec pp([_]) -> 'ok' | {'error', atom()}. 113 114pp(Disasm) -> 115 pp(group_leader(), Disasm). 116 117-spec pp(pid() | file:filename(), [_]) -> 'ok' | {'error', atom()}. 118 119pp(Stream, Disasm) when is_pid(Stream), is_list(Disasm) -> 120 NL = io_lib:nl(), 121 lists:foreach( 122 fun ({code,Code}) -> 123 lists:foreach( 124 fun (#function{name=F,arity=A,entry=E,code=C}) -> 125 io:format(Stream, "~p.~n", [{function,F,A,E}]), 126 lists:foreach( 127 fun (I) -> 128 io:put_chars(Stream, [pp_instr(I)|NL]) 129 end, C), 130 io:nl(Stream) 131 end, Code); 132 (Item) -> 133 io:format(Stream, "~p.~n~n", [Item]) 134 end, Disasm), 135 ok; 136pp(File, Disasm) when is_list(Disasm) -> 137 case file:open(File, [write]) of 138 {ok,F} -> 139 Result = pp(F, Disasm), 140 ok = file:close(F), 141 Result; 142 {error,_Reason} = Error -> Error 143 end. 144 145pp_instr({comment,I,Comment}) -> 146 [pp_instr(I)|" % "++Comment]; 147pp_instr({comment,Comment}) -> 148 ["%% "++Comment]; 149pp_instr({label,_}=I) -> 150 io_lib:format(" ~p.", [I]); 151pp_instr(I) -> 152 io_lib:format(" ~p.", [I]). 153 154-endif. 155 156%%----------------------------------------------------------------------- 157%% The main exported function 158%% File is either a file name or a binary containing the code. 159%% Call `format_error({error, Module, Reason})' for an error string. 160%%----------------------------------------------------------------------- 161 162-spec file(file:filename() | binary()) -> #beam_file{} | {'error',atom(),_}. 163 164file(File) -> 165 try process_chunks(File) 166 catch error:Reason:Stack -> 167 {error,?MODULE,{internal,{Reason,Stack}}} 168 end. 169 170%%----------------------------------------------------------------------- 171%% Interface might need to be revised -- do not depend on it. 172%%----------------------------------------------------------------------- 173 174process_chunks(F) -> 175 case beam_lib:chunks(F, [atoms,"Code","StrT", 176 indexed_imports,labeled_exports]) of 177 {ok,{Module, 178 [{atoms,AtomsList},{"Code",CodeBin},{"StrT",StrBin}, 179 {indexed_imports,ImportsList},{labeled_exports,Exports}]}} -> 180 Atoms = mk_atoms(AtomsList), 181 LambdaBin = optional_chunk(F, "FunT"), 182 Lambdas = beam_disasm_lambdas(LambdaBin, Atoms), 183 LiteralBin = optional_chunk(F, "LitT"), 184 Literals = beam_disasm_literals(LiteralBin), 185 Code = beam_disasm_code(CodeBin, Atoms, mk_imports(ImportsList), 186 StrBin, Lambdas, Literals, Module), 187 Attributes = 188 case optional_chunk(F, attributes) of 189 none -> []; 190 Atts when is_list(Atts) -> Atts 191 end, 192 CompInfo = 193 case optional_chunk(F, "CInf") of 194 none -> []; 195 CompInfoBin when is_binary(CompInfoBin) -> 196 binary_to_term(CompInfoBin) 197 end, 198 #beam_file{module = Module, 199 labeled_exports = Exports, 200 attributes = Attributes, 201 compile_info = CompInfo, 202 code = Code}; 203 Error -> Error 204 end. 205 206%%----------------------------------------------------------------------- 207%% Retrieve an optional chunk or return 'none' if the chunk doesn't exist. 208%%----------------------------------------------------------------------- 209 210optional_chunk(F, ChunkTag) -> 211 case beam_lib:chunks(F, [ChunkTag]) of 212 {ok,{_Module,[{ChunkTag,Chunk}]}} -> Chunk; 213 {error,beam_lib,{missing_chunk,_,_}} -> none 214 end. 215 216%%----------------------------------------------------------------------- 217%% Disassembles the lambda (fun) table of a BEAM file. 218%%----------------------------------------------------------------------- 219 220-type l_info() :: {non_neg_integer(), {_,_,_,_,_,_}}. 221-spec beam_disasm_lambdas('none' | binary(), gb_trees:tree(index(), _)) -> 222 'none' | [l_info()]. 223 224beam_disasm_lambdas(none, _) -> none; 225beam_disasm_lambdas(<<_:32,Tab/binary>>, Atoms) -> 226 disasm_lambdas(Tab, Atoms, 0). 227 228disasm_lambdas(<<F:32,A:32,Lbl:32,Index:32,NumFree:32,OldUniq:32,More/binary>>, 229 Atoms, OldIndex) -> 230 Info = {lookup(F, Atoms),A,Lbl,Index,NumFree,OldUniq}, 231 [{OldIndex,Info}|disasm_lambdas(More, Atoms, OldIndex+1)]; 232disasm_lambdas(<<>>, _, _) -> []. 233 234%%----------------------------------------------------------------------- 235%% Disassembles the literal table (constant pool) of a BEAM file. 236%%----------------------------------------------------------------------- 237 238-spec beam_disasm_literals('none' | binary()) -> literals(). 239 240beam_disasm_literals(none) -> none; 241beam_disasm_literals(<<_:32,Compressed/binary>>) -> 242 <<_:32,Tab/binary>> = zlib:uncompress(Compressed), 243 gb_trees:from_orddict(disasm_literals(Tab, 0)). 244 245disasm_literals(<<Sz:32,Ext:Sz/binary,T/binary>>, Index) -> 246 [{Index,binary_to_term(Ext)}|disasm_literals(T, Index+1)]; 247disasm_literals(<<>>, _) -> []. 248 249%%----------------------------------------------------------------------- 250%% Disassembles the code chunk of a BEAM file: 251%% - The code is first disassembled into a long list of instructions. 252%% - This list is then split into functions and all names are resolved. 253%%----------------------------------------------------------------------- 254 255beam_disasm_code(<<_SS:32, % Sub-Size (length of information before code) 256 _IS:32, % Instruction Set Identifier (always 0) 257 _OM:32, % Opcode Max 258 _L:32,_F:32, 259 CodeBin/binary>>, Atoms, Imports, 260 Str, Lambdas, Literals, M) -> 261 Code = binary_to_list(CodeBin), 262 try disasm_code(Code, Atoms, Literals) of 263 DisasmCode -> 264 Functions = get_function_chunks(DisasmCode), 265 Labels = mk_labels(local_labels(Functions)), 266 [function__code_update(Function, 267 resolve_names(Is, Imports, Str, 268 Labels, Lambdas, Literals, M)) 269 || Function = #function{code=Is} <- Functions] 270 catch 271 error:Rsn -> 272 ?NO_DEBUG('code disassembling failed: ~p~n', [Rsn]), 273 ?exit(Rsn) 274 end. 275 276%%----------------------------------------------------------------------- 277 278disasm_code([B|Bs], Atoms, Literals) -> 279 {Instr,RestBs} = disasm_instr(B, Bs, Atoms, Literals), 280 [Instr|disasm_code(RestBs, Atoms, Literals)]; 281disasm_code([], _, _) -> []. 282 283%%----------------------------------------------------------------------- 284%% Splits the code stream into chunks representing the code of functions. 285%% 286%% NOTE: code actually looks like 287%% label L1: ... label Ln: 288%% func_info ... 289%% label entry: 290%% ... 291%% <on failure, use label Li to show where things died> 292%% ... 293%% So the labels before each func_info should be included as well. 294%% Ideally, only one such label is needed, but the BEAM compiler 295%% before R8 didn't care to remove the redundant ones. 296%%----------------------------------------------------------------------- 297 298get_function_chunks([]) -> 299 ?exit(empty_code_segment); 300get_function_chunks(Code) -> 301 get_funs(labels_r(Code, [])). 302 303labels_r([], R) -> {R, []}; 304labels_r([{label,_}=I|Is], R) -> 305 labels_r(Is, [I|R]); 306labels_r([{line,_}=I|Is], R) -> 307 labels_r(Is, [I|R]); 308labels_r(Is, R) -> {R, Is}. 309 310get_funs({[],[]}) -> []; 311get_funs({_,[]}) -> 312 ?exit(no_func_info_in_code_segment); 313get_funs({LsR0,[{func_info,[{atom,M}=AtomM,{atom,F}=AtomF,ArityArg]}|Code0]}) 314 when is_atom(M), is_atom(F) -> 315 Arity = resolve_arg_unsigned(ArityArg), 316 {LsR,Code,RestCode} = get_fun(Code0, []), 317 [{label,[{u,Entry}]}|_] = Code, 318 [#function{name=F, 319 arity=Arity, 320 entry=Entry, 321 code=lists:reverse(LsR0, [{func_info,AtomM,AtomF,Arity}|Code])} 322 |get_funs({LsR,RestCode})]. 323 324get_fun([{func_info,_}|_]=Is, R0) -> 325 {LsR,R} = labels_r(R0, []), 326 {LsR,lists:reverse(R),Is}; 327get_fun([{int_code_end,[]}], R) -> 328 {[],lists:reverse(R),[]}; 329get_fun([I|Is], R) -> 330 get_fun(Is, [I|R]); 331get_fun([], R) -> 332 ?DEBUG('warning: code segment did not end with int_code_end~n',[]), 333 {[],lists:reverse(R),[]}. 334 335%%----------------------------------------------------------------------- 336%% Collects local labels -- I am not sure this is 100% what is needed. 337%%----------------------------------------------------------------------- 338 339local_labels(Funs) -> 340 lists:sort(lists:foldl(fun (F, R) -> 341 local_labels_1(function__code(F), R) 342 end, [], Funs)). 343 344local_labels_1(Code0, R) -> 345 Code1 = lists:dropwhile(fun({label,_}) -> true; 346 ({line,_}) -> true; 347 ({func_info,_,_,_}) -> false 348 end, Code0), 349 [{func_info,{atom,M},{atom,F},A}|Code] = Code1, 350 local_labels_2(Code, R, {M,F,A}). 351 352local_labels_2([{label,[{u,L}]}|Code], R, MFA) -> 353 local_labels_2(Code, [{L,MFA}|R], MFA); 354local_labels_2(_, R, _) -> R. 355 356%%----------------------------------------------------------------------- 357%% Disassembles a single BEAM instruction; most instructions are handled 358%% in a generic way; indexing instructions are handled separately. 359%%----------------------------------------------------------------------- 360 361disasm_instr(B, Bs, Atoms, Literals) -> 362 {SymOp, Arity} = beam_opcodes:opname(B), 363 case SymOp of 364 select_val -> 365 disasm_select_inst(select_val, Bs, Atoms, Literals); 366 select_tuple_arity -> 367 disasm_select_inst(select_tuple_arity, Bs, Atoms, Literals); 368 put_map_assoc -> 369 disasm_map_inst(put_map_assoc, Arity, Bs, Atoms, Literals); 370 put_map_exact -> 371 disasm_map_inst(put_map_exact, Arity, Bs, Atoms, Literals); 372 get_map_elements -> 373 disasm_map_inst(get_map_elements, Arity, Bs, Atoms, Literals); 374 has_map_fields -> 375 disasm_map_inst(has_map_fields, Arity, Bs, Atoms, Literals); 376 put_tuple2 -> 377 disasm_put_tuple2(Bs, Atoms, Literals); 378 make_fun3 -> 379 disasm_make_fun3(Bs, Atoms, Literals); 380 init_yregs -> 381 disasm_init_yregs(Bs, Atoms, Literals); 382 _ -> 383 try decode_n_args(Arity, Bs, Atoms, Literals) of 384 {Args, RestBs} -> 385 ?NO_DEBUG("instr ~p~n", [{SymOp, Args}]), 386 {{SymOp, Args}, RestBs} 387 catch 388 error:Rsn -> 389 ?NO_DEBUG("decode_n_args(~p,~p) failed~n", [Arity, Bs]), 390 ?exit({cannot_disasm_instr, {SymOp, Arity, Rsn}}) 391 end 392 end. 393 394%%----------------------------------------------------------------------- 395%% Disassembles a BEAM select_* instruction used for indexing. 396%% Currently handles {select_val,3} and {select_tuple_arity,3} insts. 397%% 398%% The arguments of a "select"-type instruction look as follows: 399%% <reg>, {f,FailLabel}, {list, <num cases>, [<case1> ... <caseN>]} 400%% where each case is of the form [symbol,{f,Label}]. 401%%----------------------------------------------------------------------- 402 403disasm_select_inst(Inst, Bs, Atoms, Literals) -> 404 {X, Bs1} = decode_arg(Bs, Atoms, Literals), 405 {F, Bs2} = decode_arg(Bs1, Atoms, Literals), 406 {Z, Bs3} = decode_arg(Bs2, Atoms, Literals), 407 {U, Bs4} = decode_arg(Bs3, Atoms, Literals), 408 {u, Len} = U, 409 {List, RestBs} = decode_n_args(Len, Bs4, Atoms, Literals), 410 {{Inst, [X,F,{Z,U,List}]}, RestBs}. 411 412disasm_map_inst(Inst, Arity, Bs0, Atoms, Literals) -> 413 {Args0,Bs1} = decode_n_args(Arity, Bs0, Atoms, Literals), 414 %% no droplast .. 415 [Z|Args1] = lists:reverse(Args0), 416 Args = lists:reverse(Args1), 417 {U, Bs2} = decode_arg(Bs1, Atoms, Literals), 418 {u, Len} = U, 419 {List, RestBs} = decode_n_args(Len, Bs2, Atoms, Literals), 420 {{Inst, Args ++ [{Z,U,List}]}, RestBs}. 421 422disasm_put_tuple2(Bs, Atoms, Literals) -> 423 {X, Bs1} = decode_arg(Bs, Atoms, Literals), 424 {Z, Bs2} = decode_arg(Bs1, Atoms, Literals), 425 {U, Bs3} = decode_arg(Bs2, Atoms, Literals), 426 {u, Len} = U, 427 {List, RestBs} = decode_n_args(Len, Bs3, Atoms, Literals), 428 {{put_tuple2, [X,{Z,U,List}]}, RestBs}. 429 430disasm_make_fun3(Bs, Atoms, Literals) -> 431 {Fun, Bs1} = decode_arg(Bs, Atoms, Literals), 432 {Dst, Bs2} = decode_arg(Bs1, Atoms, Literals), 433 {Z, Bs3} = decode_arg(Bs2, Atoms, Literals), 434 {U, Bs4} = decode_arg(Bs3, Atoms, Literals), 435 {u, Len} = U, 436 {List, RestBs} = decode_n_args(Len, Bs4, Atoms, Literals), 437 {{make_fun3, [Fun,Dst,{Z,U,List}]}, RestBs}. 438 439disasm_init_yregs(Bs1, Atoms, Literals) -> 440 {Z, Bs2} = decode_arg(Bs1, Atoms, Literals), 441 {U, Bs3} = decode_arg(Bs2, Atoms, Literals), 442 {u, Len} = U, 443 {List, RestBs} = decode_n_args(Len, Bs3, Atoms, Literals), 444 {{init_yregs, [{Z,U,List}]}, RestBs}. 445 446%%----------------------------------------------------------------------- 447%% decode_arg([Byte]) -> {Arg, [Byte]} 448%% 449%% - an arg can have variable length, so we must return arg + remaining bytes 450%% - decodes an argument into its 'raw' form: { Tag, Value } 451%% several types map to a single tag, so the byte code instr must then 452%% assign a type to it 453%%----------------------------------------------------------------------- 454 455-spec decode_arg([byte(),...]) -> {{disasm_tag(),_}, [byte()]}. 456 457decode_arg([B|Bs]) -> 458 Tag = decode_tag(B band 2#111), 459 ?NO_DEBUG('Tag = ~p, B = ~p, Bs = ~p~n', [Tag, B, Bs]), 460 case Tag of 461 z -> 462 decode_z_tagged(Tag, B, Bs, no_literals); 463 _ -> 464 %% all other cases are handled as if they were integers 465 decode_int(Tag, B, Bs) 466 end. 467 468-spec decode_arg([byte(),...], gb_trees:tree(index(), _), literals()) -> 469 {disasm_term(), [byte()]}. 470 471decode_arg([B|Bs0], Atoms, Literals) -> 472 Tag = decode_tag(B band 2#111), 473 ?NO_DEBUG('Tag = ~p, B = ~p, Bs = ~p~n', [Tag, B, Bs0]), 474 case Tag of 475 z -> 476 decode_z_tagged(Tag, B, Bs0, Literals); 477 a -> 478 %% atom or nil 479 case decode_int(Tag, B, Bs0) of 480 {{a,0},Bs} -> {nil,Bs}; 481 {{a,I},Bs} -> {{atom,lookup(I, Atoms)},Bs} 482 end; 483 _ -> 484 %% all other cases are handled as if they were integers 485 decode_int(Tag, B, Bs0) 486 end. 487 488%%----------------------------------------------------------------------- 489%% Decodes an integer value. Handles positives, negatives, and bignums. 490%% 491%% Tries to do the opposite of: 492%% beam_asm:encode(1, 5) = [81] 493%% beam_asm:encode(1, 1000) = [105,232] 494%% beam_asm:encode(1, 2047) = [233,255] 495%% beam_asm:encode(1, 2048) = [25,8,0] 496%% beam_asm:encode(1,-1) = [25,255,255] 497%% beam_asm:encode(1,-4294967295) = [121,255,0,0,0,1] 498%% beam_asm:encode(1, 4294967295) = [121,0,255,255,255,255] 499%% beam_asm:encode(1, 429496729501) = [121,99,255,255,255,157] 500%%----------------------------------------------------------------------- 501 502decode_int(Tag,B,Bs) when (B band 16#08) =:= 0 -> 503 %% N < 16 = 4 bits, NNNN:0:TTT 504 N = B bsr 4, 505 {{Tag,N},Bs}; 506decode_int(Tag,B,Bs) when (B band 16#10) =:= 0 -> 507 %% N < 2048 = 11 bits = 3:8 bits, NNN:01:TTT, NNNNNNNN 508 [B1|Bs1] = Bs, 509 Val0 = B band 2#11100000, 510 N = (Val0 bsl 3) bor B1, 511 ?NO_DEBUG('NNN:01:TTT, NNNNNNNN = ~n~p:01:~p, ~p = ~p~n', [Val0,Tag,B,N]), 512 {{Tag,N},Bs1}; 513decode_int(Tag,B,Bs) -> 514 {Len,Bs1} = decode_int_length(B,Bs), 515 {IntBs,RemBs} = take_bytes(Len,Bs1), 516 N = build_arg(IntBs), 517 [F|_] = IntBs, 518 Num = if F > 127, Tag =:= i -> decode_negative(N,Len); 519 true -> N 520 end, 521 ?NO_DEBUG('Len = ~p, IntBs = ~p, Num = ~p~n', [Len,IntBs,Num]), 522 {{Tag,Num},RemBs}. 523 524-spec decode_int_length(integer(), [byte()]) -> {integer(), [byte()]}. 525 526decode_int_length(B, Bs) -> 527 %% The following imitates get_erlang_integer() in beam_load.c 528 %% Len is the size of the integer value in bytes 529 case B bsr 5 of 530 7 -> 531 {Arg,ArgBs} = decode_arg(Bs), 532 case Arg of 533 {u,L} -> 534 {L+9,ArgBs}; % 9 stands for 7+2 535 _ -> 536 ?exit({decode_int,weird_bignum_sublength,Arg}) 537 end; 538 L -> 539 {L+2,Bs} 540 end. 541 542-spec decode_negative(non_neg_integer(), non_neg_integer()) -> neg_integer(). 543 544decode_negative(N, Len) -> 545 N - (1 bsl (Len*8)). % 8 is number of bits in a byte 546 547%%----------------------------------------------------------------------- 548%% Decodes lists and floating point numbers. 549%%----------------------------------------------------------------------- 550 551decode_z_tagged(Tag,B,Bs,Literals) when (B band 16#08) =:= 0 -> 552 N = B bsr 4, 553 case N of 554 0 -> % float 555 decode_float(Bs); 556 1 -> % list 557 {{Tag,N},Bs}; 558 2 -> % fr 559 decode_fr(Bs); 560 3 -> % allocation list 561 decode_alloc_list(Bs, Literals); 562 4 -> % literal 563 {{u,LitIndex},RestBs} = decode_arg(Bs), 564 case gb_trees:get(LitIndex, Literals) of 565 Float when is_float(Float) -> 566 {{float,Float},RestBs}; 567 Literal -> 568 {{literal,Literal},RestBs} 569 end; 570 _ -> 571 ?exit({decode_z_tagged,{invalid_extended_tag,N}}) 572 end; 573decode_z_tagged(_,B,_,_) -> 574 ?exit({decode_z_tagged,{weird_value,B}}). 575 576-spec decode_float([byte(),...]) -> {{'float', float()}, [byte()]}. 577 578decode_float(Bs) -> 579 {FL,RestBs} = take_bytes(8,Bs), 580 <<Float:64/float>> = list_to_binary(FL), 581 {{float,Float},RestBs}. 582 583-spec decode_fr([byte(),...]) -> {{'fr', non_neg_integer()}, [byte()]}. 584 585decode_fr(Bs) -> 586 {{u,Fr},RestBs} = decode_arg(Bs), 587 {{fr,Fr},RestBs}. 588 589decode_alloc_list(Bs, Literals) -> 590 {{u,N},RestBs} = decode_arg(Bs), 591 decode_alloc_list_1(N, Literals, RestBs, []). 592 593decode_alloc_list_1(0, _Literals, RestBs, Acc) -> 594 {{u,{alloc,lists:reverse(Acc)}},RestBs}; 595decode_alloc_list_1(N, Literals, Bs0, Acc) -> 596 {{u,Type},Bs1} = decode_arg(Bs0), 597 {{u,Val},Bs} = decode_arg(Bs1), 598 Res = case Type of 599 0 -> {words,Val}; 600 1 -> {floats,Val}; 601 2 -> {funs,Val} 602 end, 603 decode_alloc_list_1(N-1, Literals, Bs, [Res|Acc]). 604 605%%----------------------------------------------------------------------- 606%% take N bytes from a stream, return {Taken_bytes, Remaining_bytes} 607%%----------------------------------------------------------------------- 608 609-spec take_bytes(non_neg_integer(), [byte()]) -> {[byte()], [byte()]}. 610 611take_bytes(N, Bs) -> 612 take_bytes(N, Bs, []). 613 614take_bytes(N, [B|Bs], Acc) when N > 0 -> 615 take_bytes(N-1, Bs, [B|Acc]); 616take_bytes(0, Bs, Acc) -> 617 {lists:reverse(Acc), Bs}. 618 619%%----------------------------------------------------------------------- 620%% from a list of bytes Bn,Bn-1,...,B1,B0 621%% build (Bn << 8*n) bor ... bor (B1 << 8) bor (B0 << 0) 622%%----------------------------------------------------------------------- 623 624build_arg(Bs) -> 625 build_arg(Bs, 0). 626 627build_arg([B|Bs], N) -> 628 build_arg(Bs, (N bsl 8) bor B); 629build_arg([], N) -> 630 N. 631 632%%----------------------------------------------------------------------- 633%% Decodes a bunch of arguments and returns them in a list 634%%----------------------------------------------------------------------- 635 636decode_n_args(N, Bs, Atoms, Literals) when N >= 0 -> 637 decode_n_args(N, [], Bs, Atoms, Literals). 638 639decode_n_args(N, Acc, Bs0, Atoms, Literals) when N > 0 -> 640 {A1,Bs} = decode_arg(Bs0, Atoms, Literals), 641 decode_n_args(N-1, [A1|Acc], Bs, Atoms, Literals); 642decode_n_args(0, Acc, Bs, _, _) -> 643 {lists:reverse(Acc),Bs}. 644 645%%----------------------------------------------------------------------- 646%% Convert a numeric tag value into a symbolic one 647%%----------------------------------------------------------------------- 648 649-spec decode_tag(0..7) -> symbolic_tag(). 650 651decode_tag(?tag_u) -> u; 652decode_tag(?tag_i) -> i; 653decode_tag(?tag_a) -> a; 654decode_tag(?tag_x) -> x; 655decode_tag(?tag_y) -> y; 656decode_tag(?tag_f) -> f; 657decode_tag(?tag_h) -> h; 658decode_tag(?tag_z) -> z. 659 660%%----------------------------------------------------------------------- 661%% - replace all references {a,I} with the atom with index I (or {atom,A}) 662%% - replace all references to {i,K} in an external call position with 663%% the proper MFA (position in list, first elt = 0, yields MFA to use) 664%% - resolve strings, represented as <offset, length>, into their 665%% actual values by using string table 666%% (note: string table should be passed as a BINARY so that we can 667%% use binary_to_list/3!) 668%% - convert instruction to its readable form ... 669%% 670%% Currently, only the first three are done (systematically, at least). 671%% 672%% Note: It MAY be premature to remove the lists of args, since that 673%% representation means it is simpler to iterate over all args, etc. 674%%----------------------------------------------------------------------- 675 676resolve_names(Fun, Imports, Str, Lbls, Lambdas, Literals, M) -> 677 [resolve_inst(Instr, Imports, Str, Lbls, Lambdas, Literals, M) || Instr <- Fun]. 678 679%% 680%% New make_fun2/4 instruction added in August 2001 (R8). 681%% We handle it specially here to avoid adding an argument to 682%% the clause for every instruction. 683%% 684 685resolve_inst({make_fun2,Args}, _, _, _, Lambdas, _, M) -> 686 [OldIndex] = resolve_args(Args), 687 {OldIndex,{F,A,_Lbl,_Index,NumFree,OldUniq}} = 688 lists:keyfind(OldIndex, 1, Lambdas), 689 {make_fun2,{M,F,A},OldIndex,OldUniq,NumFree}; 690resolve_inst({make_fun3,[Fun,Dst,{{z,1},{u,_},Env0}]}, _, _, _, Lambdas, _, M) -> 691 OldIndex = resolve_arg(Fun), 692 Env1 = resolve_args(Env0), 693 {OldIndex,{F,A,_Lbl,_Index,_NumFree,OldUniq}} = 694 lists:keyfind(OldIndex, 1, Lambdas), 695 {make_fun3,{M,F,A},OldIndex,OldUniq,Dst,{list,Env1}}; 696resolve_inst(Instr, Imports, Str, Lbls, _Lambdas, _Literals, _M) -> 697 %% io:format(?MODULE_STRING":resolve_inst ~p.~n", [Instr]), 698 resolve_inst(Instr, Imports, Str, Lbls). 699 700resolve_inst({label,[{u,L}]},_,_,_) -> 701 {label,L}; 702resolve_inst(FuncInfo,_,_,_) when element(1, FuncInfo) =:= func_info -> 703 FuncInfo; % already resolved 704%% resolve_inst(int_code_end,_,_,_,_) -> % instruction already handled 705%% int_code_end; % should not really be handled here 706resolve_inst({call,[{u,N},{f,L}]},_,_,Lbls) -> 707 {call,N,lookup(L,Lbls)}; 708resolve_inst({call_last,[{u,N},{f,L},{u,U}]},_,_,Lbls) -> 709 {call_last,N,lookup(L,Lbls),U}; 710resolve_inst({call_only,[{u,N},{f,L}]},_,_,Lbls) -> 711 {call_only,N,lookup(L,Lbls)}; 712resolve_inst({call_ext,[{u,N},{u,MFAix}]},Imports,_,_) -> 713 {call_ext,N,lookup(MFAix+1,Imports)}; 714resolve_inst({call_ext_last,[{u,N},{u,MFAix},{u,X}]},Imports,_,_) -> 715 {call_ext_last,N,lookup(MFAix+1,Imports),X}; 716resolve_inst({bif0,Args},Imports,_,_) -> 717 [Bif,Reg] = resolve_args(Args), 718 {extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports), 719 {bif,BifName,nofail,[],Reg}; 720resolve_inst({bif1,Args},Imports,_,_) -> 721 [F,Bif,A1,Reg] = resolve_args(Args), 722 {extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports), 723 {bif,BifName,F,[A1],Reg}; 724resolve_inst({bif2,Args},Imports,_,_) -> 725 [F,Bif,A1,A2,Reg] = resolve_args(Args), 726 {extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports), 727 {bif,BifName,F,[A1,A2],Reg}; 728resolve_inst({allocate,[{u,X0},{u,X1}]},_,_,_) -> 729 {allocate,X0,X1}; 730resolve_inst({allocate_heap,[{u,X0},{u,X1},{u,X2}]},_,_,_) -> 731 {allocate_heap,X0,X1,X2}; 732resolve_inst({allocate_zero,[{u,X0},{u,X1}]},_,_,_) -> 733 {allocate_zero,X0,X1}; 734resolve_inst({allocate_heap_zero,[{u,X0},{u,X1},{u,X2}]},_,_,_) -> 735 {allocate_heap_zero,X0,X1,X2}; 736resolve_inst({test_heap,[{u,X0},{u,X1}]},_,_,_) -> 737 {test_heap,X0,X1}; 738resolve_inst({init,[Dst]},_,_,_) -> 739 {init,Dst}; 740resolve_inst({deallocate,[{u,L}]},_,_,_) -> 741 {deallocate,L}; 742resolve_inst({return,[]},_,_,_) -> 743 return; 744resolve_inst({send,[]},_,_,_) -> 745 send; 746resolve_inst({remove_message,[]},_,_,_) -> 747 remove_message; 748resolve_inst({timeout,[]},_,_,_) -> 749 timeout; 750resolve_inst({loop_rec,[Lbl,Dst]},_,_,_) -> 751 {loop_rec,Lbl,Dst}; 752resolve_inst({loop_rec_end,[Lbl]},_,_,_) -> 753 {loop_rec_end,Lbl}; 754resolve_inst({wait,[Lbl]},_,_,_) -> 755 {wait,Lbl}; 756resolve_inst({wait_timeout,[Lbl,Int]},_,_,_) -> 757 {wait_timeout,Lbl,resolve_arg(Int)}; 758resolve_inst({is_lt=I,Args0},_,_,_) -> 759 [L|Args] = resolve_args(Args0), 760 {test,I,L,Args}; 761resolve_inst({is_ge=I,Args0},_,_,_) -> 762 [L|Args] = resolve_args(Args0), 763 {test,I,L,Args}; 764resolve_inst({is_eq=I,Args0},_,_,_) -> 765 [L|Args] = resolve_args(Args0), 766 {test,I,L,Args}; 767resolve_inst({is_ne=I,Args0},_,_,_) -> 768 [L|Args] = resolve_args(Args0), 769 {test,I,L,Args}; 770resolve_inst({is_eq_exact=I,Args0},_,_,_) -> 771 [L|Args] = resolve_args(Args0), 772 {test,I,L,Args}; 773resolve_inst({is_ne_exact=I,Args0},_,_,_) -> 774 [L|Args] = resolve_args(Args0), 775 {test,I,L,Args}; 776resolve_inst({is_integer=I,Args0},_,_,_) -> 777 [L|Args] = resolve_args(Args0), 778 {test,I,L,Args}; 779resolve_inst({is_float=I,Args0},_,_,_) -> 780 [L|Args] = resolve_args(Args0), 781 {test,I,L,Args}; 782resolve_inst({is_number=I,Args0},_,_,_) -> 783 [L|Args] = resolve_args(Args0), 784 {test,I,L,Args}; 785resolve_inst({is_atom=I,Args0},_,_,_) -> 786 [L|Args] = resolve_args(Args0), 787 {test,I,L,Args}; 788resolve_inst({is_pid=I,Args0},_,_,_) -> 789 [L|Args] = resolve_args(Args0), 790 {test,I,L,Args}; 791resolve_inst({is_reference=I,Args0},_,_,_) -> 792 [L|Args] = resolve_args(Args0), 793 {test,I,L,Args}; 794resolve_inst({is_port=I,Args0},_,_,_) -> 795 [L|Args] = resolve_args(Args0), 796 {test,I,L,Args}; 797resolve_inst({is_nil=I,Args0},_,_,_) -> 798 [L|Args] = resolve_args(Args0), 799 {test,I,L,Args}; 800resolve_inst({is_binary=I,Args0},_,_,_) -> 801 [L|Args] = resolve_args(Args0), 802 {test,I,L,Args}; 803resolve_inst({is_list=I,Args0},_,_,_) -> 804 [L|Args] = resolve_args(Args0), 805 {test,I,L,Args}; 806resolve_inst({is_nonempty_list=I,Args0},_,_,_) -> 807 [L|Args] = resolve_args(Args0), 808 {test,I,L,Args}; 809resolve_inst({is_tuple=I,Args0},_,_,_) -> 810 [L|Args] = resolve_args(Args0), 811 {test,I,L,Args}; 812resolve_inst({test_arity=I,Args0},_,_,_) -> 813 [L|Args] = resolve_args(Args0), 814 {test,I,L,Args}; 815resolve_inst({is_tagged_tuple=I,Args0},_,_,_) -> 816 [F|Args] = resolve_args(Args0), 817 {test,I,F,Args}; 818resolve_inst({select_val,Args},_,_,_) -> 819 [Reg,FLbl,{{z,1},{u,_Len},List0}] = Args, 820 List = resolve_args(List0), 821 {select_val,Reg,FLbl,{list,List}}; 822resolve_inst({select_tuple_arity,Args},_,_,_) -> 823 [Reg,FLbl,{{z,1},{u,_Len},List0}] = Args, 824 List = resolve_args(List0), 825 {select_tuple_arity,Reg,FLbl,{list,List}}; 826resolve_inst({jump,[Lbl]},_,_,_) -> 827 {jump,Lbl}; 828resolve_inst({'catch',[Dst,Lbl]},_,_,_) -> 829 {'catch',Dst,Lbl}; 830resolve_inst({catch_end,[Dst]},_,_,_) -> 831 {catch_end,Dst}; 832resolve_inst({move,[Src,Dst]},_,_,_) -> 833 {move,resolve_arg(Src),Dst}; 834resolve_inst({get_list,[Src,Dst1,Dst2]},_,_,_) -> 835 {get_list,Src,Dst1,Dst2}; 836resolve_inst({get_tuple_element,[Src,{u,Off},Dst]},_,_,_) -> 837 {get_tuple_element,resolve_arg(Src),Off,resolve_arg(Dst)}; 838resolve_inst({set_tuple_element,[Src,Dst,{u,Off}]},_,_,_) -> 839 {set_tuple_element,resolve_arg(Src),resolve_arg(Dst),Off}; 840resolve_inst({put_list,[Src1,Src2,Dst]},_,_,_) -> 841 {put_list,resolve_arg(Src1),resolve_arg(Src2),Dst}; 842resolve_inst({put_tuple,[{u,Arity},Dst]},_,_,_) -> 843 {put_tuple,Arity,Dst}; 844resolve_inst({put,[Src]},_,_,_) -> 845 {put,resolve_arg(Src)}; 846resolve_inst({badmatch,[X]},_,_,_) -> 847 {badmatch,resolve_arg(X)}; 848resolve_inst({if_end,[]},_,_,_) -> 849 if_end; 850resolve_inst({case_end,[X]},_,_,_) -> 851 {case_end,resolve_arg(X)}; 852resolve_inst({call_fun,[{u,N}]},_,_,_) -> 853 {call_fun,N}; 854resolve_inst({is_function=I,Args0},_,_,_) -> 855 [L|Args] = resolve_args(Args0), 856 {test,I,L,Args}; 857resolve_inst({call_ext_only,[{u,N},{u,MFAix}]},Imports,_,_) -> 858 {call_ext_only,N,lookup(MFAix+1,Imports)}; 859%% 860%% Instructions for handling binaries added in R7A & R7B 861%% 862resolve_inst({bs_put_integer,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) -> 863 [A2,A5] = resolve_args([Arg2,Arg5]), 864 {bs_put_integer,Lbl,A2,N,decode_field_flags(U),A5}; 865resolve_inst({bs_put_binary,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) -> 866 [A2,A5] = resolve_args([Arg2,Arg5]), 867 {bs_put_binary,Lbl,A2,N,decode_field_flags(U),A5}; 868resolve_inst({bs_put_float,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) -> 869 [A2,A5] = resolve_args([Arg2,Arg5]), 870 {bs_put_float,Lbl,A2,N,decode_field_flags(U),A5}; 871resolve_inst({bs_put_string,[{u,Len},{u,Off}]},_,Strings,_) -> 872 String = if Len > 0 -> binary_to_list(Strings, Off+1, Off+Len); 873 true -> "" 874 end, 875 {bs_put_string,Len,{string,String}}; 876 877%% 878%% Instructions for handling floating point numbers added in June 2001 (R8). 879%% 880resolve_inst({fclearerror,[]},_,_,_) -> 881 fclearerror; 882resolve_inst({fcheckerror,[Arg]},_,_,_) -> 883 {fcheckerror,resolve_arg(Arg)}; 884resolve_inst({fmove,Args},_,_,_) -> 885 [FR,Reg] = resolve_args(Args), 886 {fmove,FR,Reg}; 887resolve_inst({fconv,Args},_,_,_) -> 888 [Reg,FR] = resolve_args(Args), 889 {fconv,Reg,FR}; 890resolve_inst({fadd=I,Args},_,_,_) -> 891 [F,A1,A2,Reg] = resolve_args(Args), 892 {arithfbif,I,F,[A1,A2],Reg}; 893resolve_inst({fsub=I,Args},_,_,_) -> 894 [F,A1,A2,Reg] = resolve_args(Args), 895 {arithfbif,I,F,[A1,A2],Reg}; 896resolve_inst({fmul=I,Args},_,_,_) -> 897 [F,A1,A2,Reg] = resolve_args(Args), 898 {arithfbif,I,F,[A1,A2],Reg}; 899resolve_inst({fdiv=I,Args},_,_,_) -> 900 [F,A1,A2,Reg] = resolve_args(Args), 901 {arithfbif,I,F,[A1,A2],Reg}; 902resolve_inst({fnegate,Args},_,_,_) -> 903 [F,Arg,Reg] = resolve_args(Args), 904 {arithfbif,fnegate,F,[Arg],Reg}; 905 906%% 907%% Instructions for try expressions added in January 2003 (R10). 908%% 909resolve_inst({'try',[Reg,Lbl]},_,_,_) -> % analogous to 'catch' 910 {'try',Reg,Lbl}; 911resolve_inst({try_end,[Reg]},_,_,_) -> % analogous to 'catch_end' 912 {try_end,Reg}; 913resolve_inst({try_case,[Reg]},_,_,_) -> % analogous to 'catch_end' 914 {try_case,Reg}; 915resolve_inst({try_case_end,[Arg]},_,_,_) -> 916 {try_case_end,resolve_arg(Arg)}; 917resolve_inst({raise,[_Reg1,_Reg2]=Regs},_,_,_) -> 918 {raise,{f,0},Regs,{x,0}}; % do NOT wrap this as a 'bif' 919 % as there is no raise/2 bif! 920 921%% 922%% New bit syntax instructions added in February 2004 (R10B). 923%% 924resolve_inst({bs_init2,[Lbl,Arg2,{u,W},{u,R},{u,F},Arg6]},_,_,_) -> 925 [A2,A6] = resolve_args([Arg2,Arg6]), 926 {bs_init2,Lbl,A2,W,R,decode_field_flags(F),A6}; 927resolve_inst({bs_add=I,[Lbl,Arg2,Arg3,Arg4,Arg5]},_,_,_) -> 928 [A2,A3,A4,A5] = resolve_args([Arg2,Arg3,Arg4,Arg5]), 929 {I,Lbl,[A2,A3,A4],A5}; 930 931%% 932%% New apply instructions added in April 2004 (R10B). 933%% 934resolve_inst({apply,[{u,Arity}]},_,_,_) -> 935 {apply,Arity}; 936resolve_inst({apply_last,[{u,Arity},{u,D}]},_,_,_) -> 937 {apply_last,Arity,D}; 938 939%% 940%% New test instruction added in April 2004 (R10B). 941%% 942resolve_inst({is_boolean=I,Args0},_,_,_) -> 943 [L|Args] = resolve_args(Args0), 944 {test,I,L,Args}; 945 946%% 947%% New instruction added in June 2005. 948%% 949resolve_inst({is_function2=I,Args0},_,_,_) -> 950 [L|Args] = resolve_args(Args0), 951 {test,I,L,Args}; 952 953%% 954%% New bit syntax matching added in Dec 2005 (R11B). 955%% 956resolve_inst({bs_start_match2=I,[F,Reg,{u,Live},{u,Max},Ms]},_,_,_) -> 957 {test,I,F,[Reg,Live,Max,Ms]}; 958resolve_inst({bs_get_integer2=I,[Lbl,Ms,{u,Live},Arg2,{u,N},{u,U},Arg5]},_,_,_) -> 959 [A2,A5] = resolve_args([Arg2,Arg5]), 960 {test,I,Lbl,[Ms, Live,A2,N,decode_field_flags(U),A5]}; 961resolve_inst({bs_get_binary2=I,[Lbl,Ms,{u,Live},Arg2,{u,N},{u,U},Arg5]},_,_,_) -> 962 [A2,A5] = resolve_args([Arg2,Arg5]), 963 {test,I,Lbl,[Ms, Live,A2,N,decode_field_flags(U),A5]}; 964resolve_inst({bs_get_float2=I,[Lbl,Ms,{u,Live},Arg2,{u,N},{u,U},Arg5]},_,_,_) -> 965 [A2,A5] = resolve_args([Arg2,Arg5]), 966 {test,I,Lbl,[Ms, Live,A2,N,decode_field_flags(U),A5]}; 967resolve_inst({bs_skip_bits2=I,[Lbl,Ms,Arg2,{u,N},{u,U}]},_,_,_) -> 968 A2 = resolve_arg(Arg2), 969 {test,I,Lbl,[Ms,A2,N,decode_field_flags(U)]}; 970resolve_inst({bs_test_tail2=I,[F,Ms,{u,N}]},_,_,_) -> 971 {test,I,F,[Ms,N]}; 972resolve_inst({bs_save2=I,[Ms,{u,N}]},_,_,_) -> 973 {I,Ms,N}; 974resolve_inst({bs_restore2=I,[Ms,{u,N}]},_,_,_) -> 975 {I,Ms,N}; 976resolve_inst({bs_save2=I,[Ms,{atom,_}=Atom]},_,_,_) -> 977 %% New operand type in R12B. 978 {I,Ms,Atom}; 979resolve_inst({bs_restore2=I,[Ms,{atom,_}=Atom]},_,_,_) -> 980 %% New operand type in R12B. 981 {I,Ms,Atom}; 982 983%% 984%% New instructions for guard BIFs that may GC. Added in Jan 2006 (R11B). 985%% 986resolve_inst({gc_bif1,Args},Imports,_,_) -> 987 [F,Live,Bif,A1,Reg] = resolve_args(Args), 988 {extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports), 989 {gc_bif,BifName,F,Live,[A1],Reg}; 990resolve_inst({gc_bif2,Args},Imports,_,_) -> 991 [F,Live,Bif,A1,A2,Reg] = resolve_args(Args), 992 {extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports), 993 {gc_bif,BifName,F,Live,[A1,A2],Reg}; 994 995%% 996%% New instruction in R14, gc_bif with 3 arguments 997%% 998resolve_inst({gc_bif3,Args},Imports,_,_) -> 999 [F,Live,Bif,A1,A2,A3,Reg] = resolve_args(Args), 1000 {extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports), 1001 {gc_bif,BifName,F,Live,[A1,A2,A3],Reg}; 1002 1003%% 1004%% R11B-5. 1005%% 1006resolve_inst({is_bitstr=I,Args0},_,_,_) -> 1007 [L|Args] = resolve_args(Args0), 1008 {test,I,L,Args}; 1009 1010%% 1011%% R12B. 1012%% 1013resolve_inst({bs_context_to_binary=I,[Reg0]},_,_,_) -> 1014 Reg = resolve_arg(Reg0), 1015 {I,Reg}; 1016resolve_inst({bs_test_unit=I,[F,Ms,{u,N}]},_,_,_) -> 1017 {test,I,F,[Ms,N]}; 1018resolve_inst({bs_match_string=I,[F,Ms,{u,Bits},{u,Off}]},_,Strings,_) -> 1019 Len = (Bits+7) div 8, 1020 String = if 1021 Len > 0 -> 1022 <<_:Off/binary,Bin:Len/binary,_/binary>> = Strings, 1023 Bin; 1024 true -> <<>> 1025 end, 1026 {test,I,F,[Ms,Bits,String]}; 1027resolve_inst({bs_init_writable=I,[]},_,_,_) -> 1028 I; 1029resolve_inst({bs_append=I,[Lbl,Arg2,{u,W},{u,R},{u,U},Arg6,{u,F},Arg8]},_,_,_) -> 1030 [A2,A6,A8] = resolve_args([Arg2,Arg6,Arg8]), 1031 {I,Lbl,A2,W,R,U,A6,decode_field_flags(F),A8}; 1032resolve_inst({bs_private_append=I,[Lbl,Arg2,{u,U},Arg4,{u,F},Arg6]},_,_,_) -> 1033 [A2,A4,A6] = resolve_args([Arg2,Arg4,Arg6]), 1034 {I,Lbl,A2,U,A4,decode_field_flags(F),A6}; 1035resolve_inst({trim=I,[{u,N},{u,Remaining}]},_,_,_) -> 1036 {I,N,Remaining}; 1037resolve_inst({bs_init_bits,[Lbl,Arg2,{u,W},{u,R},{u,F},Arg6]},_,_,_) -> 1038 [A2,A6] = resolve_args([Arg2,Arg6]), 1039 {bs_init_bits,Lbl,A2,W,R,decode_field_flags(F),A6}; 1040 1041%% 1042%% R12B-5. 1043%% 1044resolve_inst({bs_get_utf8=I,[Lbl,Arg2,Arg3,{u,U},Arg4]},_,_,_) -> 1045 [A2,A3,A4] = resolve_args([Arg2,Arg3,Arg4]), 1046 {test,I,Lbl,[A2,A3,decode_field_flags(U),A4]}; 1047resolve_inst({bs_skip_utf8=I,[Lbl,Arg2,Arg3,{u,U}]},_,_,_) -> 1048 [A2,A3] = resolve_args([Arg2,Arg3]), 1049 {test,I,Lbl,[A2,A3,decode_field_flags(U)]}; 1050resolve_inst({bs_get_utf16=I,[Lbl,Arg2,Arg3,{u,U},Arg4]},_,_,_) -> 1051 [A2,A3,A4] = resolve_args([Arg2,Arg3,Arg4]), 1052 {test,I,Lbl,[A2,A3,decode_field_flags(U),A4]}; 1053resolve_inst({bs_skip_utf16=I,[Lbl,Arg2,Arg3,{u,U}]},_,_,_) -> 1054 [A2,A3] = resolve_args([Arg2,Arg3]), 1055 {test,I,Lbl,[A2,A3,decode_field_flags(U)]}; 1056resolve_inst({bs_get_utf32=I,[Lbl,Arg2,Arg3,{u,U},Arg4]},_,_,_) -> 1057 [A2,A3,A4] = resolve_args([Arg2,Arg3,Arg4]), 1058 {test,I,Lbl,[A2,A3,decode_field_flags(U),A4]}; 1059resolve_inst({bs_skip_utf32=I,[Lbl,Arg2,Arg3,{u,U}]},_,_,_) -> 1060 [A2,A3] = resolve_args([Arg2,Arg3]), 1061 {test,I,Lbl,[A2,A3,decode_field_flags(U)]}; 1062resolve_inst({bs_utf8_size=I,[Lbl,Arg2,Arg3]},_,_,_) -> 1063 [A2,A3] = resolve_args([Arg2,Arg3]), 1064 {I,Lbl,A2,A3}; 1065resolve_inst({bs_put_utf8=I,[Lbl,{u,U},Arg3]},_,_,_) -> 1066 A3 = resolve_arg(Arg3), 1067 {I,Lbl,decode_field_flags(U),A3}; 1068resolve_inst({bs_utf16_size=I,[Lbl,Arg2,Arg3]},_,_,_) -> 1069 [A2,A3] = resolve_args([Arg2,Arg3]), 1070 {I,Lbl,A2,A3}; 1071resolve_inst({bs_put_utf16=I,[Lbl,{u,U},Arg3]},_,_,_) -> 1072 A3 = resolve_arg(Arg3), 1073 {I,Lbl,decode_field_flags(U),A3}; 1074resolve_inst({bs_put_utf32=I,[Lbl,{u,U},Arg3]},_,_,_) -> 1075 A3 = resolve_arg(Arg3), 1076 {I,Lbl,decode_field_flags(U),A3}; 1077 1078%% 1079%% R13B03. 1080%% 1081resolve_inst({on_load,[]},_,_,_) -> 1082 on_load; 1083 1084%% 1085%% R14A. 1086%% 1087resolve_inst({recv_mark,[Lbl]},_,_,_) -> 1088 {recv_mark,Lbl}; 1089resolve_inst({recv_set,[Lbl]},_,_,_) -> 1090 {recv_set,Lbl}; 1091 1092%% 1093%% R15A. 1094%% 1095resolve_inst({line,[Index]},_,_,_) -> 1096 {line,resolve_arg(Index)}; 1097 1098%% 1099%% 17.0 1100%% 1101resolve_inst({put_map_assoc,Args},_,_,_) -> 1102 [FLbl,Src,Dst,{u,N},{{z,1},{u,_Len},List0}] = Args, 1103 List = resolve_args(List0), 1104 {put_map_assoc,FLbl,Src,Dst,N,{list,List}}; 1105resolve_inst({put_map_exact,Args},_,_,_) -> 1106 [FLbl,Src,Dst,{u,N},{{z,1},{u,_Len},List0}] = Args, 1107 List = resolve_args(List0), 1108 {put_map_exact,FLbl,Src,Dst,N,{list,List}}; 1109resolve_inst({is_map=I,Args0},_,_,_) -> 1110 [FLbl|Args] = resolve_args(Args0), 1111 {test,I,FLbl,Args}; 1112resolve_inst({has_map_fields,Args0},_,_,_) -> 1113 [FLbl,Src,{{z,1},{u,_Len},List0}] = Args0, 1114 List = resolve_args(List0), 1115 {test,has_map_fields,FLbl,Src,{list,List}}; 1116resolve_inst({get_map_elements,Args0},_,_,_) -> 1117 [FLbl,Src,{{z,1},{u,_Len},List0}] = Args0, 1118 List = resolve_args(List0), 1119 {get_map_elements,FLbl,Src,{list,List}}; 1120 1121%% 1122%% OTP 21. 1123%% 1124 1125resolve_inst({build_stacktrace,[]},_,_,_) -> 1126 build_stacktrace; 1127resolve_inst({raw_raise,[]},_,_,_) -> 1128 raw_raise; 1129resolve_inst({get_hd,[Src,Dst]},_,_,_) -> 1130 {get_hd,Src,Dst}; 1131resolve_inst({get_tl,[Src,Dst]},_,_,_) -> 1132 {get_tl,Src,Dst}; 1133 1134%% 1135%% OTP 22. 1136%% 1137 1138resolve_inst({put_tuple2,[Dst,{{z,1},{u,_},List0}]},_,_,_) -> 1139 List = resolve_args(List0), 1140 {put_tuple2,Dst,{list,List}}; 1141resolve_inst({bs_start_match3,[Fail,Bin,Live,Dst]},_,_,_) -> 1142 {bs_start_match3,Fail,Bin,Live,Dst}; 1143resolve_inst({bs_get_tail,[Src,Dst,Live]},_,_,_) -> 1144 {bs_get_tail,Src,Dst,Live}; 1145resolve_inst({bs_get_position,[Src,Dst,Live]},_,_,_) -> 1146 {bs_get_position,Src,Dst,Live}; 1147resolve_inst({bs_set_position,[Src,Dst]},_,_,_) -> 1148 {bs_set_position,Src,Dst}; 1149 1150%% 1151%% OTP 23. 1152%% 1153 1154resolve_inst({bs_start_match4,[Fail,Live,Src,Dst]},_,_,_) -> 1155 {bs_start_match4,Fail,Live,Src,Dst}; 1156resolve_inst({swap,[_,_]=List},_,_,_) -> 1157 [R1,R2] = resolve_args(List), 1158 {swap,R1,R2}; 1159 1160%% 1161%% OTP 24. 1162%% 1163 1164resolve_inst({init_yregs,[{{z,1},{u,_},List0}]},_,_,_) -> 1165 List = resolve_args(List0), 1166 {init_yregs,{list,List}}; 1167resolve_inst({recv_marker_bind,[Mark,Ref]},_,_,_) -> 1168 {recv_marker_bind,Mark,Ref}; 1169resolve_inst({recv_marker_clear,[Reg]},_,_,_) -> 1170 {recv_marker_clear,Reg}; 1171resolve_inst({recv_marker_reserve,[Reg]},_,_,_) -> 1172 {recv_marker_reserve,Reg}; 1173resolve_inst({recv_marker_use,[Reg]},_,_,_) -> 1174 {recv_marker_use,Reg}; 1175 1176 1177%% 1178%% Catches instructions that are not yet handled. 1179%% 1180resolve_inst(X,_,_,_) -> ?exit({resolve_inst,X}). 1181 1182%%----------------------------------------------------------------------- 1183%% Resolves arguments in a generic way. 1184%%----------------------------------------------------------------------- 1185 1186resolve_args(Args) -> [resolve_arg(A) || A <- Args]. 1187 1188resolve_arg({x,N} = Arg) when is_integer(N), N >= 0 -> Arg; 1189resolve_arg({y,N} = Arg) when is_integer(N), N >= 0 -> Arg; 1190resolve_arg({fr,N} = Arg) when is_integer(N), N >= 0 -> Arg; 1191resolve_arg({f,N} = Arg) when is_integer(N), N >= 0 -> Arg; 1192resolve_arg({u,_} = Arg) -> resolve_arg_unsigned(Arg); 1193resolve_arg({i,_} = Arg) -> resolve_arg_integer(Arg); 1194resolve_arg({atom,Atom} = Arg) when is_atom(Atom) -> Arg; 1195resolve_arg({float,F} = Arg) when is_float(F) -> Arg; 1196resolve_arg({literal,_} = Arg) -> Arg; 1197resolve_arg(nil) -> nil. 1198 1199resolve_arg_unsigned({u,N}) when is_integer(N), N >= 0 -> N. 1200 1201resolve_arg_integer({i,N}) when is_integer(N) -> {integer,N}. 1202 1203%%----------------------------------------------------------------------- 1204%% The purpose of the following is just to add a hook for future changes. 1205%% Currently, field flags are numbers 1-2-4-8 and only two of these 1206%% numbers (BSF_LITTLE 2 -- BSF_SIGNED 4) have a semantic significance; 1207%% others are just hints for speeding up the execution; see "erl_bits.h". 1208%%----------------------------------------------------------------------- 1209 1210decode_field_flags(FF) -> 1211 {field_flags,FF}. 1212 1213%%----------------------------------------------------------------------- 1214%% Private Utilities 1215%%----------------------------------------------------------------------- 1216 1217mk_imports(ImportList) -> 1218 gb_trees:from_orddict([{I,{extfunc,M,F,A}} || {I,M,F,A} <- ImportList]). 1219 1220mk_atoms(AtomList) -> 1221 gb_trees:from_orddict(AtomList). 1222 1223mk_labels(LabelList) -> 1224 gb_trees:from_orddict(LabelList). 1225 1226lookup(I, Imports) -> 1227 gb_trees:get(I, Imports). 1228