BeamFile (beam_file v0.6.1)

An interface to the BEAM file format.

This module is mainly a wrapper around Erlangs :beam_lib.

For more information see the Erlang documentation for the module beam_lib

Furthermore, different code representations can be generated from the file.

To use the functions above with a module name the module must be compiled and loaded. The functions can also be used with the binary of a module.

Summary

Functions

Returns the :abstract_code chunk.

Returns chunk data for all chunks.

Same as all_chunks/ but raises BeamFile.Error

Returns the binary for the given input.

Returns the byte code for the BEAM file.

Returns infos for the given chunk reference.

Returns the infos from the :debug_info chunk.

Returns the infos from the :docs chunk.

Returns elixir code recreated from the debug_info chunk.

Returns the extended Elixir AST.

Returns the Erlang code for the BEAM file.

Returns true if a BEAM file for the given module exists.

Returns a keyword list containing some information about a BEAM file.

Returns the absolute filename for the module.

Types

@type beam() :: path() | binary()
@type chunk_id() :: charlist()

Chunk ID.

'Abst'
| 'Attr'
| 'AtU8'
| 'CInf'
| 'Dbgi'
| 'Dcos'
| 'ExCk'
| 'ExpT'
| 'ImpT'
| 'LocT'
Link to this type

chunk_name()

@type chunk_name() ::
  :abstract_code
  | :atoms
  | :attributes
  | :compile_info
  | :debug_info
  | :docs
  | :elixir_checker
  | :exports
  | :imports
  | :indexed_imports
  | :labeled_exports
  | :labeled_locals
  | :locals
@type chunk_ref() :: chunk_name() | chunk_id()
@type info() :: [
  file: Path.t() | binary(),
  module: module(),
  chunks: [{charlist(), non_neg_integer(), non_neg_integer()}]
]
@type input() ::
  beam()
  | module()
  | {:module, module(), binary(), any()}
  | [{module(), binary()}]
@type path() :: charlist()
@type reason() :: any()

Functions

Link to this function

abstract_code(input)

@spec abstract_code(input()) :: {:ok, term()} | {:error, any()}

Returns the :abstract_code chunk.

Examples

iex> BeamFile.abstract_code(BeamFile.Example)
{
  :ok,
  [
    {:attribute, 1, :file, {'test/fixtures/example.ex', 1}},
    {:attribute, 1, :module, BeamFile.Example},
    {:attribute, 1, :compile, [:no_auto_import]},
    {:attribute, 1, :export, [__info__: 1, hello: 0]},
    {
      :attribute,
      1,
      :spec,
      {
        {:__info__, 1},
        [
          {
            :type,
            1,
            :fun,
            [
              {
                :type,
                1,
                :product,
                [
                  {
                    :type,
                    1,
                    :union,
                    [
                      {:atom, 1, :attributes},
                      {:atom, 1, :compile},
                      {:atom, 1, :functions},
                      {:atom, 1, :macros},
                      {:atom, 1, :md5},
                      {:atom, 1, :exports_md5},
                      {:atom, 1, :module},
                      {:atom, 1, :deprecated},
                      {:atom, 1, :struct}
                    ]
                  }
                ]
              },
              {:type, 1, :any, []}
            ]
          }
        ]
      }
    },
    {
      :function,
      0,
      :__info__,
      1,
      [
        {:clause, 0, [{:atom, 0, :module}], [], [{:atom, 0, BeamFile.Example}]},
        {
          :clause,
          0,
          [{:atom, 0, :functions}],
          [],
          [{:cons, 0, {:tuple, 0, [{:atom, 0, :hello}, {:integer, 0, 0}]}, {nil, 0}}]
        },
        {:clause, 0, [{:atom, 0, :macros}], [], [nil: 0]},
        {:clause, 0, [{:atom, 0, :struct}], [], [{:atom, 0, nil}]},
        {
          :clause,
          0,
          [{:atom, 0, :exports_md5}],
          [],
          [
            {
              :bin,
              0,
              [
                {
                  :bin_element,
                  0,
                  {:string, 0,
                    [166, 117, 1, 22, 146, 56, 30, 199, 203, 141, 158, 223, 3, 11, 225, 190]},
                  :default,
                  :default
                }
              ]
            }
          ]
        },
        {
          :clause,
          0,
          [{:match, 0, {:var, 0, :Key}, {:atom, 0, :attributes}}],
          [],
          [
            {
              :call,
              0,
              {:remote, 0, {:atom, 0, :erlang}, {:atom, 0, :get_module_info}},
              [{:atom, 0, BeamFile.Example}, {:var, 0, :Key}]
            }
          ]
        },
        {
          :clause,
          0,
          [{:match, 0, {:var, 0, :Key}, {:atom, 0, :compile}}],
          [],
          [
            {
              :call,
              0,
              {:remote, 0, {:atom, 0, :erlang}, {:atom, 0, :get_module_info}},
              [{:atom, 0, BeamFile.Example}, {:var, 0, :Key}]
            }
          ]
        },
        {
          :clause,
          0,
          [{:match, 0, {:var, 0, :Key}, {:atom, 0, :md5}}],
          [],
          [
            {
              :call,
              0,
              {:remote, 0, {:atom, 0, :erlang}, {:atom, 0, :get_module_info}},
              [{:atom, 0, BeamFile.Example}, {:var, 0, :Key}]
            }
          ]
        },
        {:clause, 0, [{:atom, 0, :deprecated}], [], [nil: 0]}
      ]
    },
    {:function, 2, :hello, 0, [{:clause, 2, [], [], [{:atom, 2, :world}]}]}
  ]
}
Link to this function

abstract_code!(input)

@spec abstract_code!(input()) :: term()

Same as abstract_code/1 but raises BeamFile.Error

Link to this function

all_chunks(input, type \\ :names)

@spec all_chunks(input(), type :: :names | :ids) :: {:ok, map()} | {:error, any()}

Returns chunk data for all chunks.

The type argument forces the use of :ids or :names, defaults to :names.

Examples

iex> {:ok, chunks} = BeamFile.all_chunks(BeamFile.Example, :names)
iex> chunks |> Map.keys() |> Enum.sort()
[
  :abstract_code,
  :atoms,
  :attributes,
  :compile_info,
  :debug_info,
  :docs,
  :elixir_checker,
  :exports,
  :imports,
  :indexed_imports,
  :labeled_exports,
  :labeled_locals,
  :locals
]
iex> Map.get(chunks, :docs)
{:docs_v1, 1, :elixir, "text/markdown", :none, %{},
 [{{:function, :hello, 0}, 2, ["hello()"], :none, %{}}]}

iex> {:ok, chunks} = BeamFile.all_chunks(BeamFile.Example, :ids)
iex> chunks |> Map.keys() |> Enum.sort()
['Abst', 'AtU8', 'Attr', 'CInf', 'Dbgi', 'Docs', 'ExCk', 'ExpT', 'ImpT', 'LocT']
iex> chunks |> Map.get('Docs') |> is_binary()
true
Link to this function

all_chunks!(input, type \\ :names)

@spec all_chunks!(input(), type :: :names | :ids) :: map()

Same as all_chunks/ but raises BeamFile.Error

@spec binary(input()) ::
  {:ok, binary()}
  | {:error, File.posix()}
  | {:error, :non_existing | :preloaded | :cover_compiled}

Returns the binary for the given input.

@spec binary!(input()) :: binary()

Same as binary/1 but raises BeamFile.Error

Link to this function

byte_code(input)

@spec byte_code(input()) :: {:ok, term()} | {:error, any()}

Returns the byte code for the BEAM file.

Examples

iex> {:ok, byte_code} = BeamFile.byte_code(BeamFile.Example)
iex> byte_code |> Tuple.to_list() |> Enum.take(3)
[
  :beam_file,
  BeamFile.Example,
  [{:__info__, 1, 2}, {:hello, 0, 11}, {:module_info, 0, 13}, {:module_info, 1, 15}]
]
Link to this function

byte_code!(input)

@spec byte_code!(input()) :: term()

Same as byte_code/1 but raises BeamFile.Error

Link to this function

chunk(input, chunk)

@spec chunk(input(), chunk_ref()) :: {:ok, term()} | {:error, any()}

Returns infos for the given chunk reference.

Examples

iex> BeamFile.chunk(BeamFile.Example, :exports)
{:ok, [__info__: 1, hello: 0, module_info: 0, module_info: 1]}

iex> {:ok, chunk} = BeamFile.chunk(BeamFile.Example, 'Dbgi')
iex> is_binary(chunk)
true
Link to this function

chunk!(input, chunk)

@spec chunk!(input(), chunk_ref()) :: term()

Same as chunk/2 but raises BeamFile.Error

Link to this function

debug_info(input)

@spec debug_info(input()) :: {:ok, term()} | {:error, any()}

Returns the infos from the :debug_info chunk.

Examples:

iex> {:ok, info} = BeamFile.debug_info(BeamFile.Example)
iex> info |> Map.get(:definitions) |> hd() |> elem(0)
{:hello, 0}
iex> Map.get(info, :relative_file)
"test/fixtures/example.ex"
Link to this function

debug_info!(input)

@spec debug_info!(input()) :: term()

Same as debug_info/1 but raises BeamFile.Error

Link to this function

docs(input, options \\ [])

@spec docs(input(), options :: keyword()) :: {:ok, term()} | {:error, any()}

Returns the infos from the :docs chunk.

Options

  • format - the output format. The format :info reduces the output to the type and the infos :since, :hidden and :deprecated. The format since reduces the output to the type and the info :since.

  • hidden - indicates whether only hidden or none hidden items are returned. Without the option hidden and none hidden items are returned.

  • deprecated - indicates wheter only deprecated or none deprecated items are returned. Without the option deprecated and none deprecated items are returned.

  • since - expected a version requirement. With since, the function returns all items whose since attribute matches since. When since does not match the module attribute since and not any item in the module matches, the tuple {:ok, nil} is returned.

Examples

iex> BeamFile.docs(BeamFile.Example)
{:ok, {:none, %{}, [{{:function, :hello, 0}, 2, ["hello()"], :none, %{}}]}}

Examples with options (Elixir 1.16):

iex> BeamFile.docs(Float, format: :info, deprecated: true)
{:ok,
 {[
    {{:function, :to_char_list, 1}, [since: nil, hidden: true, deprecated: true]},
    {{:function, :to_char_list, 2}, [since: nil, hidden: true, deprecated: true]},
    {{:function, :to_string, 2}, [since: nil, hidden: true, deprecated: true]}
  ], [since: nil, hidden: false, deprecated: false]}}

iex> BeamFile.docs(Date, format: :since, since: "~> 1.12")
{:ok,
 {[
    {{:function, :after?, 2}, [since: "1.15.0"]},
    {{:function, :before?, 2}, [since: "1.15.0"]},
    {{:function, :range, 3}, [since: "1.12.0"]}
  ], [since: nil]}}
Link to this function

docs!(input, options \\ [])

@spec docs!(input(), [{:options, keyword()}]) :: term()

Same as docs/2 but raises BeamFile.Error

Link to this function

elixir_code(input, opts \\ [])

@spec elixir_code(input(), opts :: keyword()) :: {:ok, String.t()} | {:error, any()}

Returns elixir code recreated from the debug_info chunk.

The recreated code comes with resolved macros and references. For now, types and specs will not be recreated.

Options: :docs: With docs: true the docs will be created.

Examples

iex> BeamFile.elixir_code(BeamFile.Example)
{
  :ok,
  """
  defmodule Elixir.BeamFile.Example do
    def hello do
      :world
    end
  end\
  """
}
Link to this function

elixir_code!(input, opts \\ [])

@spec elixir_code!(input(), opts :: keyword()) :: String.t()

Same as elixir_code/1 but raises BeamFile.Error

Link to this function

elixir_quoted(input)

@spec elixir_quoted(input()) :: {:ok, Macro.t()} | {:error, any()}

Returns the extended Elixir AST.

Link to this function

elixir_quoted!(input)

@spec elixir_quoted!(input()) :: Macro.t()

Same as elixir_quoted/1 but raises BeamFile.Error

Link to this function

erl_code(input)

@spec erl_code(input()) :: {:ok, String.t()} | {:error, any()}

Returns the Erlang code for the BEAM file.

Examples

iex> {:ok, code} = BeamFile.erl_code(BeamFile.Example)
iex> code =~ "-module('Elixir.BeamFile.Example')"
true
Link to this function

erl_code!(input)

@spec erl_code!(input()) :: String.t()

Same as erl_code/1 but raises BeamFile.Error

Link to this function

exists?(module)

@spec exists?(module()) :: boolean()

Returns true if a BEAM file for the given module exists.

Examples

iex> BeamFile.exists?(BeamFile.Example)
true
iex> BeamFile.exists?(Physics.TOE)
false
@spec info(input()) :: {:ok, info()} | {:error, reason()}

Returns a keyword list containing some information about a BEAM file.

  • :file: The name of the BEAM file, or the binary from which the information was extracted.
  • :module: The name of the module.
  • :chunks: For each chunk, the identifier and the position and size of the chunk data, in bytes.

Examples

iex> {:ok, info} = BeamFile.info(BeamFile.Example)
iex> info[:module]
BeamFile.Example
iex> info[:chunks]
...> |> Enum.map(fn {id, _pos, _size} -> id end)
...> |> Enum.sort()
[
  'AtU8',
  'Attr',
  'CInf',
  'Code',
  'Dbgi',
  'Docs',
  'ExCk',
  'ExpT',
  'ImpT',
  'Line',
  'LitT',
  'LocT',
  'StrT',
  'Type'
]
@spec which(module()) ::
  {:ok, Path.t()} | {:error, :non_existing | :preloaded | :cover_compiled}

Returns the absolute filename for the module.

If the module cannot be found, {:error, :non_existing} is returned.

If the module is preloaded, {:error, :preloaded} is returned.

If the module is Cover-compiled, {:error, :cover_compiled} is returned.

Examples

iex> {:ok, path} = BeamFile.which(BeamFile.Example)
iex> path =~ "/_build/test/lib/beam_file/ebin/Elixir.BeamFile.Example.beam"
@spec which!(module()) :: Path.t()

Same as which/1 but raises BeamFile.Error