Marcus
BeamFile - An interface to the BEAM file format and a decompiler
BeamFile is mainly a wrapper around the Erlang module :beam_lib.
BeamFile provides different views to the data in a BEAM file: BeamFile.elixir_code/2, BeamFile.erl_code/1, BeamFile.abstract_code/1 and BeamFile.byte_code/1. The reconstructed Elixir code is not the original code. In this code all macros and reference are resolved.
Example:
defmodule Say do
def hello(name \\ "World"), do: name |> format() |> puts()
def format(name), do: "Hello, #{name}!"
defdelegate puts(item), to: IO
end
iex> {:ok, code} = BeamFile.elixir_code(Say)
iex> IO.puts(code)
defmodule Elixir.Say do
def hello(name) do
puts(format(name))
end
def hello do
hello("World")
end
def format(name) do
<<"Hello, ", String.Chars.to_string(name)::binary(), "!">>
end
def puts(item) do
IO.puts(item)
end
end
:ok
iex> {:ok, code} = BeamFile.erl_code(Say)
iex> IO.puts(code)
file("test/fixtures/default.ex", 7).
-module('Elixir.Say').
-compile([no_auto_import]).
-export(['__info__'/1,
format/1,
hello/0,
hello/1,
puts/1]).
-spec '__info__'(attributes |
compile |
functions |
macros |
md5 |
exports_md5 |
module |
deprecated) -> any().
'__info__'(module) -> 'Elixir.Say';
'__info__'(functions) ->
[{format, 1}, {hello, 0}, {hello, 1}, {puts, 1}];
'__info__'(macros) -> [];
'__info__'(exports_md5) -> <<"VÑ>Qlf`zâ\202--*ÐP®">>;
'__info__'(Key = attributes) ->
erlang:get_module_info('Elixir.Say', Key);
'__info__'(Key = compile) ->
erlang:get_module_info('Elixir.Say', Key);
'__info__'(Key = md5) ->
erlang:get_module_info('Elixir.Say', Key);
'__info__'(deprecated) -> [].
format(_name@1) ->
<<"Hello, ",
case _name@1 of
_@1 when erlang:is_binary(_@1) -> _@1;
_@1 -> 'Elixir.String.Chars':to_string(_@1)
end/binary,
"!">>.
hello() -> hello(<<"World">>).
hello(_name@1) -> puts(format(_name@1)).
puts(_item@1) -> 'Elixir.IO':puts(_item@1).
:ok
iex> {:ok, code} = BeamFile.byte_code(Say)
iex> IO.inspect(code)
{:beam_file, Say,
[
{:__info__, 1, 2},
{:format, 1, 9},
{:hello, 0, 13},
{:hello, 1, 15},
{:module_info, 0, 19},
{:module_info, 1, 21},
{:puts, 1, 17}
], [vsn: [328337295702536866380643469106329237584]],
[
version: '7.6.7',
options: [:dialyzer, :no_spawn_compiler_process, :from_core,
:no_core_prepare, :no_auto_import],
source: '.../say.ex'
],
[
{:function, :__info__, 1, 2,
[
{:label, 1},
{:line, 0},
{:func_info, {:atom, Say}, {:atom, :__info__}, 1},
{:label, 2},
{:select_val, {:x, 0}, {:f, 1},
{:list,
[
atom: :attributes,
f: 7,
atom: :compile,
f: 7,
atom: :deprecated,
f: 6,
atom: :exports_md5,
f: 5,
atom: :functions,
f: 4,
atom: :macros,
f: 6,
atom: :md5,
f: 7,
atom: :module,
f: 3
]}},
{:label, 3},
{:move, {:atom, Say}, {:x, 0}},
:return,
{:label, 4},
{:move, {:literal, [format: 1, hello: 0, hello: 1, puts: 1]}, {:x, 0}},
:return,
{:label, 5},
{:move,
{:literal,
<<86, 209, 62, 81, 108, 102, 96, 122, 226, 130, 45, 45, 42, 208, 80,
174>>}, {:x, 0}},
:return,
{:label, 6},
{:move, nil, {:x, 0}},
:return,
{:label, 7},
{:move, {:x, 0}, {:x, 1}},
{:move, {:atom, Say}, {:x, 0}},
{:line, 0},
{:call_ext_only, 2, {:extfunc, :erlang, :get_module_info, 2}}
]},
{:function, :format, 1, 9,
[
{:line, 1},
{:label, 8},
{:func_info, {:atom, Say}, {:atom, :format}, 1},
{:label, 9},
{:allocate, 1, 1},
{:move, {:x, 0}, {:y, 0}},
{:test, :is_binary, {:f, 10}, [x: 0]},
{:move, {:y, 0}, {:x, 0}},
{:jump, {:f, 11}},
{:label, 10},
{:init, {:y, 0}},
{:line, 1},
{:call_ext, 1, {:extfunc, String.Chars, :to_string, 1}},
{:label, 11},
{:line, 1},
{:gc_bif, :byte_size, {:f, 0}, 1, [x: 0], {:x, 1}},
{:bs_add, {:f, 0}, [{:x, 1}, {:integer, 8}, 1], {:x, 1}},
{:line, 1},
{:bs_init2, {:f, 0}, {:x, 1}, 0, 2, {:field_flags, 0}, {:x, 1}},
{:bs_put_string, 7, {:string, 'Hello, '}},
{:bs_put_binary, {:f, 0}, {:atom, :all}, 8, {:field_flags, 0}, {:x, 0}},
{:bs_put_string, 1, {:string, '!'}},
{:move, {:x, 1}, {:x, 0}},
{:deallocate, 1},
:return
]},
{:function, :hello, 0, 13,
[
{:line, 2},
{:label, 12},
{:func_info, {:atom, Say}, {:atom, :hello}, 0},
{:label, 13},
{:move, {:literal, "World"}, {:x, 0}},
{:call_only, 1, {Say, :hello, 1}}
]},
{:function, :hello, 1, 15,
[
{:line, 2},
{:label, 14},
{:func_info, {:atom, Say}, {:atom, :hello}, 1},
{:label, 15},
{:allocate, 0, 1},
{:line, 2},
{:call, 1, {Say, :format, 1}},
{:call_last, 1, {Say, :puts, 1}, 0}
]},
{:function, :puts, 1, 17,
[
{:line, 3},
{:label, 16},
{:func_info, {:atom, Say}, {:atom, :puts}, 1},
{:label, 17},
{:line, 3},
{:call_ext_only, 1, {:extfunc, IO, :puts, 1}}
]},
{:function, :module_info, 0, 19,
[
{:line, 0},
{:label, 18},
{:func_info, {:atom, Say}, {:atom, :module_info}, 0},
{:label, 19},
{:move, {:atom, Say}, {:x, 0}},
{:line, 0},
{:call_ext_only, 1, {:extfunc, :erlang, :get_module_info, 1}}
]},
{:function, :module_info, 1, 21,
[
{:line, 0},
{:label, 20},
{:func_info, {:atom, Say}, {:atom, :module_info}, 1},
{:label, 21},
{:move, {:x, 0}, {:x, 1}},
{:move, {:atom, Say}, {:x, 0}},
{:line, 0},
{:call_ext_only, 2, {:extfunc, :erlang, :get_module_info, 2}}
]}
]}
Most Liked
Marcus
Version 0.5.0 is released. I have added BeamFile.elixir_quoted/1 to get the AST from the beam file. All functions now accept {:module, Foo, <<...>>, []} as input. With this change experiments in the iex are simpler.
iex(1)> defmodule Foo do
...(1)> def bar(x), do: if x == 0, do: false, else: true
...(1)> end |> BeamFile.elixir_code!() |> IO.puts()
defmodule Elixir.Foo do
def bar(x) do
case :erlang.==(x, 0) do
false -> true
true -> false
end
end
end
:ok
iex(2)> defmodule Foo do
...(2)> def bar(x), do: if x == 0, do: false, else: true
...(2)> end |> BeamFile.elixir_quoted!()
{:defmodule, [context: Elixir, import: Kernel],
[
{:__aliases__, [alias: false], [Foo]},
[
do: {:__block__, [],
[
{:def, [line: 4],
[
{:bar, [], [{:x, [version: 0, line: 4], nil}]},
[
do: {:case, [line: 4, optimize_boolean: true],
[
{{:., [line: 4], [:erlang, :==]}, [line: 4],
[{:x, [version: 0, line: 4], nil}, 0]},
[
do: [
{:->, [generated: true, line: 4], [[false], true]},
{:->, [generated: true, line: 4], [[true], false]}
]
]
]}
]
]}
]}
]
]}
6
Marcus
Version 0.6.0 has been released with some updates to work with Elixir 1.16.
The function BeamFileDocs now has some options for formatting and filtering the output:
iex(1)> BeamFile.docs(Date, since: "~> 1.12", format: :since)
{:ok,
{[
{{:function, :after?, 2}, [since: "1.15.0"]},
{{:function, :before?, 2}, [since: "1.15.0"]},
{{:function, :range, 3}, [since: "1.12.0"]}
], [since: nil]}}
iex(2)> BeamFile.docs(Enum, format: :info, deprecated: true)
{:ok,
{[
{{:function, :chunk, 2}, [since: nil, hidden: true, deprecated: true]},
{{:function, :chunk, 3}, [since: nil, hidden: true, deprecated: true]},
{{:function, :chunk, 4}, [since: nil, hidden: true, deprecated: true]},
{{:function, :filter_map, 3}, [since: nil, hidden: true, deprecated: true]},
{{:function, :partition, 2}, [since: nil, hidden: true, deprecated: true]},
{{:function, :uniq, 2}, [since: nil, hidden: true, deprecated: true]}
], [since: nil, hidden: false, deprecated: false]}}
5
Popular in Libraries
TypeCheck: Fast and flexible runtime type-checking for your Elixir projects.
Core ideas
Type- and function specifications are const...
New
I’ve been working on two packages (not on hex.pm yet) to build admin interfaces for phoenix apps:
bureaucrat - which contains a bunch ...
New
I released Doggo, a collection of unstyled Phoenix components.
Features
Unstyled Phoenix components.
Storybook that can be added to...
New
simple_feature_flags is a tiny package that lets you turn features on or off based on which environment (e.g. localhost, staging, product...
New
https://www.conduitframework.com/
The best overview for how things are tied together is this presentation. Modules and functions are pre...
New
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
Hello everyone,
I wrote a small library today called MapDiff.
It returns a map listing the (smallest amount of) changes to get from map...
New
ExApi is a library that I’m developing now and hope release soon
This library will allow to:
list all apis
list all api implementation...
New
Hi everyone!
I’m thrilled to announce a huge thing. We have been developing Elixir Moon Design System for quite a while. We are finally ...
New
With HEEX released we decided to start a components library using Tailwind CSS - check it out here: Petal Components.
We also have a boi...
New
Other popular topics
Manning 2016 Halloween weekend sale via Deal of the Day
Friday, October 28 - Half off all MEAPs - code WM102816LT
Saturday, October 29 ...
New
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
Hi,
I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
I tried installing
elixir 1.11.2
erlang 23.3.4
via asdf in my zsh shell. Enabled the versions locally and globally.
When I list them ...
New
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Hi,
I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
I will often find my self writing things similar to:
case some_value do
nil -> something()
"" -> something()
_ -> someth...
New
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including.
What is Phoenix LiveV...
New
Hello guys,
I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New







