tim2CF
Decompile BEAM files to Elixir source code
Is it possible to decompile BEAM files with :debug_info chunk to actual Elixir source code? This data is from :debug_info
iex(2)> Secret |> :code.which |> :beam_lib.chunks([:debug_info]) |> elem(1) |> elem(1) |> Keyword.get(:debug_info) |> elem(2) |> elem(1) |> Map.get(:definitions)
[{{:hello, 0}, :def, [line: 26], [{[line: 26], [], [], :world}]}]
And this is actual Elixir AST
iex(3)> quote do
...(3)> defmodule Secret do
...(3)> def hello, do: :world
...(3)> end
...(3)> end
{:defmodule, [context: Elixir, import: Kernel],
[
{:__aliases__, [alias: false], [:Secret]},
[
do: {:def, [context: Elixir, import: Kernel],
[{:hello, [context: Elixir], Elixir}, [do: :world]]}
]
]}
If it’s possible to transform :debug_info to AST - please write how, thanks!
Most Liked Responses
Marcus
I have also done some experiments with the BEAM file. See the little beam_file project.
With BeamFile you can create byte, erl, and elixir-code (with the limitation discussed here) from the beam file.
Example:
defmodule Example.Math do
@moduledoc "Math is Fun"
def add(number_a, number_b), do: number_a + number_b
def odd_or_even(a) do
if rem(a, 2) == 0 do
:even
else
:odd
end
end
end
iex> {:ok, code} = BeamFile.elixir_code(Example.Math)
iex> IO.puts(code)
defmodule Elixir.Example.Math do
@moduledoc """
Math is Fun
"""
def add(number_a, number_b) do
:erlang.+(number_a, number_b)
end
def odd_or_even(a) do
case(:erlang.==(:erlang.rem(a, 2), 0)) do
false ->
:odd
true ->
:even
end
end
end
olafura
My project works with a lot of code but not all code:
cdegroot
The problem is that the transformation from Elixir to BEAM bytecode loses information. A simple example:
a = 1
a = 2
will result in bytecode somewhat like
a = 1
a1= 2
Because rebinding variables isn’t possible in bytecode, so Elixir fakes it. There are plenty of such examples. Decompiling BEAM bytecode to Erlang is fairly straightforward and precise, but getting back to the original Elixir AST is, I think, almost impossible. The simpler solution would be to just stash the AST in a BEAM segment (the format is pretty extensible so while I’m not sure whether this is already happening somewhere, I’m sure it is not too hard to do this).








