Worker/Job:
- Add job listener hooks for when work actually begins for a job,
and when a job is suspended to wait for user input.
- Add hook for setting a job description string, and implement in several
subclasses.
LoadImageDebugInfoJob:
- Get rid of ImageDebugInfoJobListener since its functionality can be
handled via the more general job wait for user input hook. Refactor
accordingly.
TeamDebugger:
- Adjust to use new job hooks. When a worker job is initiated, we now
check if the job has a description, and if so pass it on to the UI
to display a notification.
DwarfLoadingStateHandler:
- Notify the UI when a package download is in progress.
With these changes, the status bar now notifies the user if any of the
following actions are in flight:
1) Loading/parsing debug information
2) Stack trace retrieval
3) Source code retrieval
4) Downloading a debug info package
ThreadHandler:
- Simplify SetBreakpointAndRun() to always use the debugger interface to
continue execution, since the latter is now intelligent enough to determine
how to handle that in all cases. Adjust callers accordingly.
- SetBreakpointAndRun() now takes an additional argument indicating if this
invocation is for a fresh run of a team or not, as continuing the thread's
execution needs to be done differently in the two cases.
- When evaluating a breakpoint condition, there's no need to change
the thread state unless the condition is actually met. This would
lead to lots of unnecessary state switching and associated overhead
in the GUI.
ExpressionInfo:
- No longer stores an explicit result type (this is inferred from
evaluation of the expression itself now).
- Introduce class ExpressionResult for returning the result of an
expression computation. This can currently take the form of either
a primitive value, or a value node object.
- Adjust UserInterfaceListener and ExpressionInfo::Listener to take
the above changes into account, and correspondingly adjust all
callers/listeners.
CLanguageExpressionEvaluator:
- Introduce child class Operand. This subsumes the functionality that
was previously in the separate Number class, and can represent a
primitive value, a value node or a type. Also has functionality to
implicity handle type promotion/inferring when performing calculations
between operands.
- Adjust expression parser to operate in terms of Operands rather than
Numbers. This allows a number of improvements, most notably that an
expression can now return a value node as a result rather than only
a primitive number. This capability isn't yet fully used, but paves
the way for future uses such as an expression that evaluates to a data
member, a global variable, or an arbitrary pointer of a particular type.
- Various cleanups/simplifications that were possible as a result of the above
changes.
ExpressionEvaluationWindow/ExpressionPromptWindow:
- Remove type menu field, since the expression API no longer uses it.
Adding/removing expressions in the VariablesView is temporarily disabled,
pending some further rework there to properly handle the new result object.
Team:
- Remove expression evaluation event / listener hook. This doesn't
really belong to the Team anyways.
UserInterfaceListener:
- ExpressionEvaluationRequested() now takes an ExpressionInfo object
rather than the individual subcomponents.
ExpressionEvaluationJob:
- Notification of expression evaluation completion is now handled
via the info object's listener interface rather than the Team.
Others:
- Adjust all users of expressions to set themselves up as
ExpressionInfo::Listener subclasses, and consequently add themselves
to the respective info object when requesting evaluation. This
significantly simplifies various things, and also ensures that no
one accidentally gets notified of an expression they didn't actually
ask for, which could occur with the previous Team-based listener
interface. Make all other required adjustments for new interface
usage.
No functional change intended.
- Ask the architecture for a stack trace directly, as we only
need the top frame.
- Properly update thread state before we go into condition
evaluation. Otherwise, other parts of the debugger potentially
wouldn't notice that we had continued execution in the case
where the condition evaluates to false, and would indicate a
program stop at the breakpoint erroneously.
ThreadHandler:
- When a breakpoint event is hit, we now check if there is an
associated UserBreakpoint with a condition attached. If so,
we schedule an evaluation request, and only stop the thread if
that one evaluates to true (or if evaluation fails in some way).
This implements #9713.
Add a listener interface for LoadImageDebugInfoJob that allows it to request
user assistance based on its current state. Adjust callers to pass in said
listener accordingly.
Implement the aforementioned listener interface in TeamDebugger, and use the
loading state handler roster to find the appropriate handler / handle the request.
This implements most of what's needed for #10138, the main piece still missing
is for the dwarf handler to detect whether the image in question comes from a package,
and if so, to offer to install the corresponding debug information package rather than
locating the file manually, assuming such a package exists.
The post syscall debug events used for output capture have an
unfortunate side effect: when asked to debug a thread, the thread is
interrupted, which, if currently blocked in a syscall will cause it to
unblock and send a post syscall event indicating such. However, this
will also absorb the debug stop flag that was set by the initial debug
request, and so we won't actually get the separate event indicating
thread debugged.
Consequently, we now set a pending stop request flag on the
corresponding Thread object, and check if it's set when processing
syscall events. If so, we treat such an event as having triggered a
debug stop even though the received event type is not explicitly
B_DEBUGGER_MESSAGE_THREAD_DEBUGGED.
- UserInterfaceListener/TeamDebugger: Extend ThreadActionRequested()
to allow passing a target address. Adjust TeamDebugger's
implementation accordingly.
- ThreadHandler: The MSG_THREAD_RUN action can now optionally take an
address parameter to run until. If this is specified, set a temporary
breakpoint for said address before resuming execution.
- SourceView: On right click, present a context menu showing possible
actions for the current line if we're currently in a stopped thread.
For the moment, this only yields the "Run to cursor" action, but
more will be added in the future.
A similar problem to that described in my previous commit afflicted the
step out case as well. We now store the current IP when issuing a step
out, and use that as the function address once execution returns.
When using step over to step out of a function, we need to use the
address range of the step statement to determine the function which
returned said value, not the current IP, as that has already exited the
function and will consequently be that of the caller, leading to such
returns being attributed to the wrong function, and consequently also
the wrong type.
- Replace use of address + CpuState pair in Thread,
SpecificImageDebugInfo::CreateStackTrace() with a ReturnValueInfoList.
Adjust all implementing subclasses and callers accordingly.
- DwarfImageDebugInfo::CreateReturnValue() -> CreateReturnValues().
Now processes a list of return value information structures rather
than just a single one. This means we can now handle multiple return
values in a single statement. This still isn't entirely correct though,
since, e.g. for functions whose return types fit in a register we need
to either retrieve them immediately after function return, or store the
CPU state at that point in time for later use in value retrieval,
otherwise the return values will all be those of the last called function.
- When we detect that we're stepping over a function call, also store
the CPU state at the time it occurred. This information is needed
in order to correctly reconstruct target addresses later since some
operands may be register-based.
- Add the aforementioned CPU state to CreateFrame()'s arguments and
adjust implementations and callers accordingly.
- ArchitectureX86 now hands off the work for GetInstructionInfo() to
DisassemblerX86, since the latter has all the information we need
to properly classify and evaluate instructions. Correspondingly a
CpuState is passed down to it in order to perform address calculations
for the instruction if it's a jump or call instruction. The latter's
targets are then stored on the thread for later retrieval when
constructing a stack trace. Adjust X86_64 accordingly for the
signature changes. This also fixes a bug where Step Over would
sometimes result in a Step Into instead due to the previous
implementation of GetInstructionInfo() occasionally failing to
classify call instructions correctly.
- Architecture::CreateStackTrace() now takes an argument specifying
the address of the last executed function if applicable. This is used
to decide who/where to decode a return value from. Adjust callers.
- DwarfImageDebugInfo::_CreateReturnValue() uses the above information
in order to know directly who the caller it needs to look up a return
value for is, rather than trying to walk backwards to find them.
Type resolution is now also a bit more sophisticated due to various
cases where the subprogram entry didn't directly contain the return
type but referred to another DIE that did. Retrieving return value
now appears to work properly in all cases except when position
independent code is involved. The latter however will require
resolving the appropriate function address in the PLT, which will
need some additional work.
- Thread now has a data member indicating if a subroutine was
executed during the last set of steps.
- ThreadHandler now sets the aforementioned state appropriate during
Step Over/Step Out.
- Architecture::CreateStackTrace() now takes a parameter indicating
whether return value retrieval is desired (based on aforementioned
thread value). Adjust callers accordingly.
- DwarfImageDebugInfo: If return value retrieval is requested, loop
backwards from the current IP to find the call instruction.
- CreateStackTrace() now takes a parameter indicating whether or not
to try and retrieve full frame information. This in turn is passed
on to SpecificImageDebugInfo, where e.g. DwarfImageDebugInfo can
use it to avoid constructing variables and parameters. This is
used by ThreadHandler since, when it requests the top frame for
its stepping calculations, this additional data/work is completely
unnecessary.