|Debugger Links. email@example.com (Naresh Chainani) (2000-04-25)|
|Re: Debugger Links. bob.zulawnik@NOSPAM.cportcorp.com (Bob Zulawnik) (2000-04-26)|
|Re: Debugger Links. firstname.lastname@example.org (Joachim Durchholz) (2000-04-30)|
|From:||Bob Zulawnik <bob.zulawnik@NOSPAM.cportcorp.com>|
|Date:||26 Apr 2000 02:43:09 -0400|
1. What code is being added/modified by the debugger ?
Usually, the only modifications performed by debugger on executing
code involve setting breakpoints. Please note that this is being done
to the code already loaded into memory, i.e. no modifications are
applied to the executable file (Also note that the user can explicitly
patch executing code under debugger, but of course this is entirely
different from modifications done by debugger 'on its own').
Setting a breakpoint usually means overlaying the original instruction
with a special break instruction (saving the original one first), or
with an invalid op-code for machines that do not have those.
Breakpoints allow for single-stepping of a program. When there is a
normal OS present, the drudgery of decoding an instruction and placing
a breakpoint after it (either on the next instruction or on possible
'landing places' in case of branches/calls etc.) falls onto the
OS. The debugger merely requests that the process be single-stepped
(for example via ptrace() call or via appropriate procfs request) and
it is the kernel that performs all the dirty work. On embedded systems
with no OS present, it is the debugger that has to perform these
functions (strictly speaking it is usually some debug agent working on
behalf of the debugger, as the debugger itself runs on some remote
host, capable of running it).
Some CPUs (notably x86) provide a hardware support for
single-stepping. It is a single-step bit, which when toggled causes
single-stepping (i.e. trapping after executing a single user-mode
instruction). In this case there is no need to place breakpoints.
2. Debugger and the traced process as master and slave.
In general the debugger places breakpoints in the executing image,
tells the OS what events are of interest to it (e.g. on systems with
procfs the debugger can request that the process be stopped upon entry
to/exit from a system call, every time a new thread is created or an
existing thread is removed etc.), then it tells the OS to schedule the
traced process for execution and it enters a waiting loop itself. It
will be notified when the traced process is stopped for any reason. In
that sense it is a master-slave relationship, with the kernel playing
the role of a go-between (in addition to being the foundation of
everything on the system).
3. 'Stop modify'.
If I understand correctly what you mean by 'stop modify for a value',
you are asking about watchpoints. They are a mechanism for catching
any changes in a variable value (write watchpoints) or even stopping
whenever a variable is being accessed (read watchpoints). If a CPU
has hardware support for watchpoints (similar to hardware support for
single-stepping) things are simple - the debugger merely requests that
any write to an address (range of addresses) or a read from an address
cause a trap. In this case it is the hardware itself that catches any
and all accesses to a given address. On systems with no hardware
support for watchpoints, but with memory management hardware, it is
possible to perform the following trick - the debugger figures out
where a given variable lives (which memory page) and then it requests
that the OS mark that page as read-only. Any attempt to write to that
page will cause exception. At that time the debugger will request that
the page be marked writeable, it will then request that the process be
single-stepped and finally it will see whether the variable under
watch has changed. If so, this will be reported to the user. If not,
the page will be marked as read-only again and the execution will
continue at full speed. Read watchpoints can be produced this way by
even taking away the 'read' bit for the given page (or range of
pages). Of course it becomes the debugger responsibility to deal with
'false hits' (writes to variables that just happen to live in the same
memory page as the one being watched). This method does not work well
for stacklocals (making stack read-only), only for global
variables. As a last resort so-called software watchpoints are used -
the program is single- stepped and after each step the value is
checked for changes. Needless to say this is very slow.
I am not aware of any Web pages giving a high-level overview of
debugger internals. There are some sites and mailing lists devoted to
gdb, but they usually assume knowledge of debuggers in general and gdb
internals in particular; in other words - you can always read gdb
sources to see how things are done (at least by this particular
On the other hand I know of 2 good books devoted to debugger internals
'How Debuggers Work' by Rosenberg (published by Wiley in 1996)
'Debugging Applications' by Robbins (published by Microsoft in 2000).
Return to the
Search the comp.compilers archives again.