Current section
Files
Jump to
Current section
Files
lib/ether.ex
defmodule Ether do
@moduledoc """
`Ether` provides the default macros and functions for debugging
your applications.
Besides the functions available in this module, the `Int` module
exposes more advanced functionality exposed in erlang's debugger
interface module.
"""
### NOTES ###
# Two different UI modes
# :dbg_wx_trace - For the wx ui at :debugger.start
# :dbg_ui_trace - For windows ui?
@doc """
Starts the graphical debugger
start() -> {status, pid} | :error | :ok
start(mode) -> {status, pid} | :error | :ok
"""
def start() do
:debugger.start()
end
def start(mode) when mode==:local or mode==:global do
:debugger.start(mode)
end
@doc """
Stops the graphical debugger
stop() -> :error | :ok
"""
def stop() do
:debugger.stop()
end
@doc """
Starts the graphical debugger
Loads the module
Attaches the debugger to the process upon start
## Examples
iex> quick_start(Integer, :to_string, [3])
"3"
quick_start(module, function, args) -> result
"""
def quick_start(module, function, args) do
start() # Start the debugger if it's not started already
load(module) # Load the module
auto_attach([:init]) # Attach the debugger upon module start
:erlang.apply(module, function, args) # Call the function with args
end
@doc """
Loads the module by name
## Examples
iex> Ether.load(Ether)
{:module, Ether}
load(module) -> {:module, module}
"""
def load(module), do: Int.i(module)
@doc """
Unloads the module by name
## Examples
iex> Ether.unload(Ether)
:ok
unload(module) -> :error | :ok
"""
def unload(module), do: Int.n(module)
@doc """
Checks what modules have been loaded
loaded?() -> [modules]
loaded?(module) -> true | false
"""
def loaded?(), do: Int.interpreted
def loaded?(module), do: Enum.member?(loaded?, module)
@doc """
Attaches the debugger
Flags:
:init - Upon Initialization
:break - Upon Break
:exit - Upon Exit
## Examples
iex> Ether.attach([:init])
:ok
attach(flags) -> :ok, false
"""
def attach(flags), do: auto_attach(flags)
defp auto_attach(flags) do
case which_gui() do
:gs -> :int.auto_attach(flags, {:dbg_ui_trace, :start, []})
:wx -> :int.auto_attach(flags, {:dbg_wx_trace, :start, []})
end
end
defp which_gui() do
try do
:wx.new()
:wx.destroy()
:wx
catch
_ -> :gs
end
end
@doc """
Displays information about what the debugger is attached to
attached?() -> {flags, function} | false
"""
def attached?(), do: Int.auto_attach
@doc """
Unattaches the debugger
unattach() -> :ok
"""
def unattach(), do: Int.auto_attach(false)
@doc """
List all breakpoints
breakpoints() ->
"""
def breakpoints(), do: Int.all_breaks()
@doc """
Enable a breakpoint for a module at a specified line number
## Examples
iex> Ether.enable_breakpoint(Ether, 134)
:ok
enable_breakpoint(module, line) -> :ok
"""
def enable_breakpoint(module, line) do
Int.enable_break(module, line)
end
@doc """
Enable many or all breakpoints
enable_breakpoints() -> :ok
enable_breakpoints([{module, line}]) -> :ok
"""
def enable_breakpoints() do
list = Enum.map Int.all_breaks, fn({x,_}) -> x end
enable_breakpoints list
end
def enable_breakpoints(breakpoints) when is_list breakpoints do
breakpoints |>
Enum.each fn({{mod, line}, _options}) -> Int.enable_break(mod, line) end
end
@doc """
Disable a breakpoint for a module at a specified line number
## Examples
iex> Ether.disable_breakpoint(Ether, 134)
:ok
disable_breakpoint(module, line) -> :ok
"""
def disable_breakpoint(module, line) do
Int.disable_breakpoint(module, line)
end
@doc """
Disable many or all breakpoints
disable_breakpoints() -> :ok
disable_breakpoints([{module, line}]) -> :ok
"""
def disable_breakpoints() do
list = Enum.map Int.all_breaks, fn({x,_}) -> x end
disable_breakpoints list
end
def disable_breakpoints(breakpoints) when is_list breakpoints do
breakpoints |>
Enum.each fn({mod, line}) -> Int.disable_break(mod, line) end
end
@doc """
Delete a breakpoint for a module at a specified line number
## Examples
iex> Ether.delete_breakpoint(module, line)
:ok
delete_breakpoint(module, line) -> :ok | {:error, :function_not_found}
"""
def delete_breakpoint(module, line) do
Int.delete_breakpoint(module, line)
end
@doc """
Delete many or all breakpoints
delete_breakpoints() -> :ok
delete_breakpoints([{module, line}]) -> :ok | :error
"""
def delete_breakpoints(), do: Int.no_break
def delete_breakpoints(breakpoints) do
breakpoints |>
Enum.each fn({{mod, line}, _options}) -> Int.delete_break(mod, line) end
end
@doc """
Add a breakpoint
## Examples
iex> Ether.add_breakpoint(Ether, 123)
:ok
iex> Ether.add_breakpoint(Ether, 123, fn -> IO.puts "Broken" end)
:ok
add_breakpoint(module, line) -> :ok | {:error, :break_exists}
add_breakpoint(module, line, action) -> :ok | {:error | :break_exists}
"""
def add_breakpoint(module, line) do
Int.break(module, line)
end
def add_breakpoint(module, line, action) do
status = Int.break(module, line)
set_action(module, line, action)
status
end
@doc """
Sets an action upon breaking
set_action(module, line, action) -> :ok
"""
def set_action(module, line, action) do
Int.action_at_break(module, line, action)
end
########################################
# Actions while attached
########################################
@doc """
Resume the debugger
resume(meta_pid) -> :ok
"""
def resume(meta_pid) when is_pid meta_pid do
Int.continue(meta_pid)
end
@doc """
Suspend the debugger
suspend(meta_pid) -> :ok
"""
def suspend(meta_pid) when is_pid meta_pid do
:dbg_icmd.stop(meta_pid)
end
@doc """
Step into
step_into(pid) -> :ok
"""
def step_into(pid) do
Int.step(pid)
end
@doc """
Step over
step_over(pid) -> :ok
"""
def step_over(pid) do
Int.next(pid)
end
@doc """
Step out of
step_out(pid) -> :ok
"""
def step_out(pid) do
Int.finish(pid)
end
@doc """
"""
end