Skip to content

Instantly share code, notes, and snippets.

@okeuday
Created January 21, 2014 20:19
Show Gist options
  • Save okeuday/8547587 to your computer and use it in GitHub Desktop.
Save okeuday/8547587 to your computer and use it in GitHub Desktop.
decompile.erl
-module(decompile).
-export([file/1]).
file(ModuleName) when is_atom(ModuleName) ->
case code:which(ModuleName) of
BeamFilePath when is_list(BeamFilePath) ->
file(BeamFilePath);
Error when is_atom(Error) ->
Error
end;
file(BeamFilePath) when is_list(BeamFilePath) ->
{beam_file,
ModuleName,
ModuleExports,
_VSN, % can be stripped (is 'none' if stripped)
ModuleAttributes, % can be stripped (is 'none' if stripped)
FunctionsList} = beam_disasm:file(BeamFilePath),
{ok,
{ModuleName,
[{abstract_code,
AbstractCode}]}} = beam_lib:chunks(BeamFilePath, [abstract_code]),
Line = 3,
FormsFake = abstract_body(abstract_header(ModuleName,
ModuleExports,
ModuleAttributes),
FunctionsList, Line),
AbstractCodeFake = {raw_abstract_v1, FormsFake},
SourceFake = erl_prettypr:format(erl_syntax:form_list(tl(FormsFake))),
io:format("0 ~p~n", [FunctionsList]),
%io:format("1 ~p~n", [AbstractCodeFake]),
%io:format("2 ~p~n", [AbstractCode]),
%io:format("3 ~s~n", [SourceFake]),
ok.
abstract_body(Output, [], Line) ->
lists:reverse([{eof, Line + 1} | Output]);
abstract_body(Output, [{function, module_info, 0, _, _} | Functions], Line) ->
abstract_body(Output, Functions, Line);
abstract_body(Output, [{function, module_info, 1, _, _} | Functions], Line) ->
abstract_body(Output, Functions, Line);
abstract_body(Output, [{function, Name, Arity, Entry, Body} | Functions], _) ->
Line = Entry + 1,
{Function, NewLine} = abstract_function(Body, Line),
abstract_body([{function, Line, Name, Arity, Function} | Output],
Functions, NewLine).
abstract_function(Body, Line) ->
abstract_function([], Body, Line).
abstract_function(Output, [], Line) ->
% {clause, Line, VariablesList, _, Body}
{[{clause, Line, [], [], lists:reverse(Output)}], Line + 1};
abstract_function(Output, [{label, Entry} | Body], _) ->
Line = Entry + 1,
abstract_function(Output, Body, Line);
abstract_function(Output, [{func_info, {atom, _M}, {atom, _F},
_Arity} | Body], Line) ->
abstract_function(Output, Body, Line);
abstract_function(Output, [_ | Body], Line) ->
%XXX
% {allocate, CountY, CountX} % allocate registers?
% {test, GuardFunction, {f, Line}, RegisterList}
% {move, RegisterSrc, RegisterDst}
% Register == {X, I} where I >= 0, I < Count
% (X == x or X == y)
abstract_function(Output, Body, Line).
abstract_header(ModuleName, ModuleExports, ModuleAttributes) ->
Line = 1,
[{attribute, Line + 1, export, abstract_exports(ModuleExports)},
{attribute, Line , module, ModuleName},
{attribute, Line , file, {abstract_filename(ModuleAttributes), 1}}].
abstract_filename(none) ->
"undefined.erl";
abstract_filename(ModuleAttributes) when is_list(ModuleAttributes) ->
case lists:keyfind(source, 1, ModuleAttributes) of
false ->
abstract_filename(none);
{source, FilePath} ->
FilePath
end.
abstract_exports(L) ->
abstract_exports([], L).
abstract_exports(Exports, []) ->
lists:reverse(Exports);
abstract_exports(Exports, [{module_info, 0, _Line} | L]) ->
abstract_exports(Exports, L);
abstract_exports(Exports, [{module_info, 1, _Line} | L]) ->
abstract_exports(Exports, L);
abstract_exports(Exports, [{Function, Arity, _Line} | L]) ->
abstract_exports([{Function, Arity} | Exports], L).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment