Decompile BEAM files to Elixir source code

It’s possible to generate it for an Elixir file using @compile (tip from this issue):

# in foo.ex
defmodule Foo do
  @compile :dprecg

  def foo(a, b) do
    a + b
  end
end

then compiling with elixir foo.ex complains:

$ elixir foo.ex
** (CompileError) foo.ex: could not compile module Foo. We expected the compiler to return a .beam binary but got something else. This usually happens because ERL_COMPILER_OPTIONS or @compile was set to change the compilation outcome in a way that is incompatible with Elixir

but does produce a foo.ex.precodegen file:

# foo.ex.precodegen
module 'Elixir.Foo'.
exports [{'__info__',1},{foo,2},{module_info,0},{module_info,1}].
attributes [].

%% Counter = 16
function `'Elixir.Foo'`:`'__info__'`(x0/_0) {
  %% _0: 0..1 0..2 10..11 14..15
0:
  [1] switch x0/_0, ^3, [
    { `attributes`, ^13 },
    { `compile`, ^13 },
    { `deprecated`, ^8 },
    { `exports_md5`, ^10 },
    { `functions`, ^9 },
    { `macros`, ^8 },
    { `md5`, ^13 },
    { `module`, ^7 }
  ]

7:
  [3] ret `'Elixir.Foo'`

9:
  [5] ret `[{foo,2}]`

10:
  [7] ret `<<63,179,243,139,216,207,23,209,142,119,33,235,17,74,57,60>>`

8:
  [9] ret `[]`

13:
  %% @ssa_ret:6: 11..13
  [11] x0/@ssa_ret:6 = call (`erlang`:`get_module_info`/2), `'Elixir.Foo'`, x0/_0
  [13] ret x0/@ssa_ret:6

3:
  %% @ssa_ret:14: 15..17
  [15] x0/@ssa_ret:14 = match_fail `function_clause`, x0/_0
  [17] ret x0/@ssa_ret:14
}

%% foo.ex:4
%% Counter = 4
function `'Elixir.Foo'`:`foo`(x0/_0, x1/_1) {
  %% _0: 0..1
  %% _1: 0..1
0:
  %% foo.ex:5
  %% _2: 1..7
  [1] x0/_2 = bif:'+' x0/_0, x1/_1

  %% @ssa_bool: 3..5
  [3] z0/@ssa_bool = succeeded x0/_2
  [5] br z0/@ssa_bool, ^3, ^1

3:
  [7] ret x0/_2

1:
  %% @ssa_ret: 9..11
  [9] x0/@ssa_ret = call (`erlang`:`error`/1), `badarg`
  [11] ret x0/@ssa_ret
}

%% Counter = 4
function `'Elixir.Foo'`:`module_info`() {
0:
  %% @ssa_ret:3: 1..3
  [1] x0/@ssa_ret:3 = call (`erlang`:`get_module_info`/1), `'Elixir.Foo'`
  [3] ret x0/@ssa_ret:3
}

%% Counter = 4
function `'Elixir.Foo'`:`module_info`(x0/_0) {
  %% _0: 0..1
0:
  %% @ssa_ret:3: 1..3
  [1] x0/@ssa_ret:3 = call (`erlang`:`get_module_info`/2), `'Elixir.Foo'`, x0/_0
  [3] ret x0/@ssa_ret:3
}
1 Like