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 Announcing
Hi there,
for my project DBLSQD, I needed a file storage solution that is a bit more flexible than Arc. Because I thought others might f...
New
Let’s write a database! Well not really, but I think it’s a little sad that there doesn’t seem to be a simple in-memory distributed KV da...
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
Hello!
Came here to announce ChromicPDF, a pet project PDF generator I’ve been working on for the past few months. Why another PDF gener...
New
Image is an image processing library for Elixir. It is based upon the fabulous vix library that provides a libvips wrapper for Elixir.
I...
New
Hi everyone,
I’ve been working on this protobuf library for 3 years. We use it in the company I work for, EasyMile, to communicate with ...
New
parameterized pipe in elixir: |n>
edit: negative index in |n> and mixed usage with |> are supported
example:
use ParamPipe
...
New
Hi! Today, after a couple weeks of development I’ve released v0.1 of LiveVue.
It’s a seamless integration of Vue and Phoenix LiveView, i...
New
I feel kind of stuck with the absence of a proper xml library for Elixir. Currently I use SweetXML which was ok for me more or less to pa...
New
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries.
offset-based pagination with...
New
Other popular topics
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible.
total = 10
while total != 0
...
New
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
If I have a post route which an argument:
post /my_post_route/:my_param1, MyController.my_post_handler
How would get the post params ...
New
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
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
Hi folks,
Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
New
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar.
I p...
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
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









