- When reading the areas note, there was no check in place to ensure that a
matching segment for the address was actually found. This would later lead
to a crash when attempting to read memory from the corresponding (missing)
piece of memory in the core.
- Don't remove .eh_frame in the linker scripts, as this saves little
space in practice, and results in debug binaries of the runtime loader
not being properly debuggable due to missing canonical frame
information.
- Rather than the previous (reverted) approach of tracking the last selected
stack frame from within the StackTraceView, we now do so from the TeamWindow,
where the selection can be mapped by thread. This fixes a subtle issue where,
due to a lack of contextual information, the stack trace view would restore
the remembered last selected frame rather than an explicitly chosen one. This
was most noticeable upon selecting a function that had a corresponding stack
frame in the current stack trace, where, instead of selecting that frame,
the existing one would remain highlighted, even though the state of all other
views had updated. Found while investigating the cause of #13710.
TeamWindow:
- When changing the active function, we would also attempt to select a stack
frame matching that function. However, in the case where the active function
was set via changing stack frames, this logic would break if the function was
recursive, and would cause the topmost frame to be selected instead of one at
the desired recursion depth.
ConnectionConfigWindow:
- When notified that settings have been changed by the current config view,
validate them, and if complete, enable the connect button.
- Implement message handler for connect button.
NetworkConnectionConfigView:
- Port input field is now prepopulated with the default remote debug port
number.
- Changes to either field now trigger listener notifications.
NetworkTargetHostInterface:
- Fix missing initializer. This would lead to a crash in the destructor.
NetworkTargetHostInterfaceInfo:
- Implement IsConfigured() to validate passed in settings.
- When adding the TargetHostInterfaceInfos to the roster, Init() was not
called on the individual instances, leading to them potentially being
incomplete.
ThreadsTableModel:
- When returning field values for the stop reason column, only return valid if
we actually populated it with a value (ergo, the thread was actually
stopped). Otherwise, the table will attempt to perform comparisons on a
BVariant which was never actually populated, leading to crashes.
- According to the Be Book, one of BListItem::Update()'s responsibilities
is updating the item's internal height/width. However, while we were
providing such updates in the case of the item initially being added
to the view, or when the list view's font was changed, we were not doing
so on frame resize. This would lead to items having a stale width field
in such a circumstance, leading to possibly incorrect behavior in apps
relying on that field to be correct.
DebugReportGenerator:
- In the case where the function was already disassembled beforehand,
we weren't retrieving the statement, leading to a null pointer
dereference.
Team:
- Adjust report generation event to include a final status code for listeners.
CliContext,TeamWindow,ReportUserinterface:
- Use aforementioned status code to indicate whether report generation
succeeded or failed.
DebugReportGenerator:
- Notify listeners if report generation fails. This may have previously
been responsible for some bug reports where it was indicated that the
debugger hung without exiting after being asked to save a report from
a crashed app.
- When dumping disassembly, retrieve it directly if necessary rather than
requesting it via the user interface listener. This also fixes the quirk
that requesting to save a crash report while looking at the source code
of a function would trigger switching it to disassembly visually.
- When walking the list of threads to dump, acquire references to all of
them before starting. Otherwise, it was potentially possible for a running
but not crashed thread to exit while we were generating the report, leaving
us with a pointer to a deleted thread. This was most likely the cause of one
of the crashes reported in #13082.
- When receiving the notification that source code state has changed, clear
the waiting function. Otherwise, it was potentially possible for us to get
other state change notifications, leading to the data semaphore being
released too often. This would then cause later potential waits such as
the stack frame memory dump to not actually wait when they should,
potentially leading them to dereference objects that weren't yet ready.
This fixes another of the crashes in #13802.
DebugReportGenerator:
- Due to the changes made with respect to correctly handling switching to
disassembly explicitly, the report generator needs to request loading
source files as it walks the stack trace in order to get source-based
line number information. Fixes crash reports having -1 as the line number
in cases where debug information was available, but the user hadn't yet
looked at the source file in question.
LoadSourceCodeJob:
- Cleanup.
ElfFile:
- The refactoring in commit 2c50fbb8e1
inadvertently introduced a failure case if a section in the ELF file
is skipped, since it was explicitly passing in the insertion index
to BObjectList::AddItem(). Since in the skipped case, this would be
out of bounds for the list's current size, this would cause the whole
operation to fail with an out of memory error, and consequently halt
all further loading of debug information for that particular file.
This manifested itself with libroot on at least gcc5, where no symbols
could be seen.
Debugger:
- Initialize/Deinitialize roster as appropriate.
ConnectionConfigWindow:
- Implement config view listener interface, and use roster
to retrieve and add appropriate config view when switching
between interface types.
ConnectionConfigHandler:
- Abstract base class for the different types of connection that allows one to
retrieve an appropriate configuration view based on the target host interface
type. This will allow the configuration window to switch dynamically between
network, USB, etc. without having to know the details of any of those.
Initially only a network subclass has been implemented though.
ConnectionConfigHandlerRoster:
- Keeps track of the list of available config handlers, and handles mapping a
request for a given interface info to the appropriate type of handler.
ConnectionConfigView:
- Abstract base class for the actual configuration views returned by the config
handlers. This exposes a listener interface via which the view can notify
an interested party that the configuration has been changed. Correspondingly,
the configuration window will use this to determine if the configuration is
complete enough to allow a connection attempt.
TeamsWindow:
- Create new connection button now sends a message to the main app,
which manages the connection window as a singleton.
Debugger:
- Handle creating/showing connection configuration window as requested.
ConnectionConfigWindow:
- Utility window that is spawned in response to requests to create a new
remote host connection. Allows setting up and attempting to make a
connection.
- Split MessageCodes.h into a second file that separates out the
application-specific message codes from those used by the core.
Adjust includes accordingly. No functional change.
TeamsWindow:
- Add Listener interface for selected target host interface changes.
- Add menu field to display/choose between active host connections.
- Add button to create a new connection (not yet functional).
TeamsListView:
- Implement TeamsWindow Listener interface to decide when to update
the displayed team list.
- Remove unused current team ID.
FunctionInstance:
- Add new state FUNCTION_SOURCE_SUPPRESSED. This signals that the user
explicitly forced disassembly to be loaded despite source code being
available.
LoadSourceCodeJob:
- When forced to disassembly, use the above suppressed state accordingly.
SourceView/TeamWindow/TeamDebugger:
- Adjust to take new state into account as needed.
TeamDebugInfo::GetActiveSourceCode:
- When looking at a function to decide whether to return line information
based on source or disassembly, first examine the source code state. If
the source has never been loaded for that function, but we have it available,
set it on the function at that point. This lazily addresses the fact that
LoadSourceCodeJob is called on behalf of a specific function, and
consequently only sets the source code onto that function, and not all others
present in the same file. This allows us to differentiate between the case
where a function doesn't have source code available at all, versus a function
that has simply been forced to disassembly view at this point in time.
The primary symptom of the above issue was that attempting to set a breakpoint
outside of the currently active function, but within the same file would result
in the breakpoints view indicating that the breakpoint was at line 0 rather
than the appropriate line, and breakpoints would also not be drawn in the
source view for such locations.
Thanks to Humdinger for the heads up!
- Add new interface TeamFunctionSourceInformation. Currently this
exposes a single function allowing one to query for the currently
active source code given a FunctionDebugInfo instance.
- Implement TeamFunctionSourceInformation on TeamDebugInfo.
- Pass TeamFunctionSourceInformation to Dwarf{Team,Image}DebugInfo.
In turn, make use of it in DwarfImageDebugInfo::GetStatement() in
order to determine whether to return the corresponding assembly
or source statement.
With this piece of information, the debugger is now correctly able to
determine that the user is currently looking at disassembly despite debug
info being available, and consequently adjust its stepping behavior based on
that. Previously, the source code statement was always used, leading to it
not being possible to single step assembly lines in such a circumstance
without manually using run to cursor.
Other related cleanups:
- TeamDebugInfo now inherits BReferenceable directly, rather than relying on
indirectly inheriting it from TeamTypeInformation.
- Remove BReferenceable from TeamTypeInformation. The latter is only an
interface anyways, and inheriting that base class from multiple locations
was causing GCC5 trouble when resolving BReference<TeamDebugInfo>, even
when virtual inheritance was used.
LocatableFile:
- If there is no parent path, don't insert a path separator between parent
and filename. This may be the case depending on how the source file was
specified during compilation.
FileManager:
- When constructing an EntryPath from a LocatableEntry, ensure that the
parent folder actually has a path string that isn't simply empty to ensure
consistency with the raw dir/file case. Otherwise, hash lookups that are
dependent on the parent dir being NULL if not specified will fail, causing
us to not locate the file successfully. This was preventing us from updating
source location information for make 4.2's main.c, as the latter was
specified in such a way that the above combination of conditions would
occur, and consequently when asking the FileManager to update the source
location with the actual file, the entry couldn't be found in the table,
and no information would be updated.
ThreadHandler:
- When single stepping, verify that current instruction pointer is
actually within a valid image. Otherwise we'll crash attempting to
retrieve debug information for it.
DwarfImageDebugInfo:
- While computing return value locations, we need to re-evaluate
the availability of debug information as we're forced to traverse
around images to resolve the location of a function call. Otherwise,
we may crash as one of the called functions may belong to an image
that wasn't compiled with debug info.
- Introduce base classes RemoteDebug{Request,Response} and the first set of
implementing subclasses for the various types of debug requests. These
encapsulate the information needed to make a request to the target debugger
interface, as well as a means to flatten/unflatten to a BMessage. These will
be used to marshal the relevant information for transmission across the
eventual transport interface. Not used anywhere yet since there still remain
some requests and responses to implement, among other things.
Architecture:
- Store and provide accessor for the size in bytes of the low-level
debug_cpu_state size of the respective target CPU. Adjust subclasses
to pass in the appropriate size information.
- Split into separate subdirectories for each interface type, as is done in
the target_host_interface subdir. Preparation for the remote interfaces,
which will have quite a few more components than the existing local ones.
UserInterface:
- Add Clone() function to set of required virtuals. This asks the subclass
to create a new instance of its respective type.
{CommandLine,Graphical,Report}UserInterface:
- Implement the above function.
TeamDebugger:
- Add accessor for the currently active UI.
TargetHostInterface:
- Set correct request type when setting up the options for a team restart.
- Ask the TeamDebugger for its user interface and clone it in order to fill
in that aspect of the debug options. This fixes a regression introduced in
commit 880a64, which inadvertently resulted in team restarts no longer
working.
- Ensure that the debugger lib's headers are included before those of libshared
to minimize conflicts between the respective Thread classes. Fixes gcc2 build.
Thanks to Jerome for reporting.
- Add subfolder src/kits/debugger which contains the debugger's core
functionality and lower layers. Correspondingly add headers/private/debugger
for shared headers to be used by clients such as the Debugger application
and eventual remote_debug_server. Adjust various files to account for
differences as a result of the split and moves.
- Add libdebugger.so to minimal Jamfile.
- Add new source file DebuggerGlobals, which contains the relevant
functions for initializing/destroying the various singleton rosters
that the core subsystems rely upon. It is the app's responsibility
to ensure these are called before anything else, and as final cleanup
at exit.
- The GUI/CLI app objects now take care of initializing the settings factory
and ValueHandlerRoster, as those are entirely app-specific.
- Refactor calls to init functions appropriately.
- SettingsManager is now a pure virtual interface. The debugger core provides
a no-op implementation of it which is used by default if no explicit manager
is provided by the client requesting a new TeamDebugger. This allows consumers
of the debugger core that have no need for settings persistence such as the
report generator to not have to care about that particular detail at all.
- Add subclass DebuggerSettingsManager which is essentially the previous
existing implementation. This one will go with the application portion
of the Debugger once the separation of app and lib has been completed.
Adjust callers accordingly.
- Refactor TeamUiSettingsFactory into an abstract base class with implementing
subclass DebuggerUiSettingsFactory.
- Adjust SettingsManager to expect the UiSettingsFactory to be passed in as an
initialization parameter, and refactor accordingly.
- Move GuiTeamUiSettings.* into a user_interface/gui subfolder.
No functional change, simply reorganization towards splitting the debugger's
core functionality into a separate library from the application to aid in
sharing with remote_debug_server.
TargetHostInterface:
- Adjust _StartTeamDebugger to always require a user interface object to
be passed in rather than implicitly falling back to GUI if unspecified.
Debugger:
- Refactor to be in compliance with the above.
- Messages that expect a reply are now tagged with a unique ID field to
indicate that expectation to the receiving socket messenger.
- The messenger now maintains a map of received reply IDs and their
corresponding messages, along with a message queue of other unsolicited
replies.
- After successfully connecting, the messenger now spawns a thread
whose sole responsibility is receiving and parsing all incoming messages,
and consequently sorting them into the aforementioned data structures based
on the presence of the reply ID. Callers who are awaiting either replies or
other messages are signalled appropriately via a semaphore. This allows
multiplexing of both types of messages on the same socket.
- Introduces new network API class BSocketMessenger, allowing one to send
and receive BMessages across a network socket in a BMessenger-like
fashion. Still very much WIP, hence currently not exposed via public headers.
Based partly on previous work by Axel.
B{Abstract,Datagram,Secure}Socket:
- Add functionality to listen for and accept new connections, thus allowing
one to use the socket classes for server functionality as well.
BSecureSocket:
- Adjust to take into account differences between how SSL needs to be called
when accepting an incoming connection vs initiating an outbound one.
The handshake on the accepted connection stills fails for unknown reasons
at the moment though.
Note that these changes break the ABI, and thus any packages making use of
them directly will need a rebuild.
UserInterfaceListener:
- Add request hook for writing a core file. Implement in TeamDebugger.
Jobs/WriteCoreFileJob:
- Add new job to actually dispatch the core file request via the debugger
interface.
Team{::Listener}
- Add listener event + hook for notifications when a core file gets written.
Implement in CLI.
CliContext:
- Add event flag for core file changed.
CommandLineUserInterface:
- Add 'write-core' command. This optionally takes a path to write the core to,
otherwise one is automatically generated by, similarly to debug reports. As
such, one can now generate cores for things like app_server and registrar
crashes if desired, in addition to reports.
- During the TargetHostInterface refactoring, a parameter was accidentally
omitted for the debugger options in the command line and report interfaces,
leading to a crash during TeamDebugger init.
{CoreFile,Local}DebuggerInterface:
- Add virtual hook for requesting a core dump of the current team. Implement
accordingly in LocalDebuggerInterface, and add a no-op stub in
CoreFileDebuggerInterface.
GraphicalUserInterface:
- The Show() method now checks if the team window is already visible. If
it is, we instead call Activate() to focus it. Fixes the problem that
attempting to attach to a team which we already had a running team
debugger for would appear to do nothing, rather than focusing that window.
TeamDebugger:
- Add accessor to query whether the debugger's interface is a post mortem core
rather than a live team.
TargetHostInterface:
- When asked to locate a team debugger by team_id, as is done for attach
requests to determine if we already have an existing instance attached, skip
over post mortems. This takes care of the potential problem of detecting a
core instance with the same team_id as a live team, and consequently refusing
the attach request.
- When a team debugger quits, use its actual pointer to look it up rather than its
team ID, as we could otherwise potentially remove the wrong one in the case of a
clash.
{Local}TargetHostInterface:
- Add virtual method for requesting a debugger interface for a core file.
Implement accordingly in LocalTargetHostInterface based on Ingo's
previous implementation in the Debugger app.
TeamDebuggerOptions:
- Add an enum to define the type of team debugger request being made
to explicitly make this clear rather than guessing based on the provided
arguments. Set accordingly in the various cases.
- Add a parameter for the core file path.
Debugger:
- Refactor to fill in TeamDebuggerOptions appropriately for core file
requests, and consequently simplify code.
This doesn't yet deal with the fact that a post-mortem team's ID can
clash with that of a live team, which may lead to issues when attempting
to attach to a live team in such a case.
TargetHostInterfaceRoster:
- Add Listener interface. For now, this simply notifies the listener of
changes to the active debugger count.
- Adjust show new team window command to automatically fall back to the local
interface window if one isn't specified. Fixes the Start New Team menu item
in the TeamWindow. The latter will later be expanded to show the available
interfaces to start a new team on in a submenu.
Debugger:
- Implement roster listener interface in order to know when to attempt
application quit.
With this commit, all necessary work to isolate the application from the target
host is complete, and work on the actual remote interface and protocol can
begin.
TargetHostInterfaceRoster:
- Implement TargetHostInterface's Listener interface. This allows us
to more cheaply track the total number of running team debuggers,
as well as automatically removing an interface that is destroyed.
Application objects:
- Rework and simplify to take into account that they will no longer be
directly managing the team debugger list. Requests to start a new debugger
are still funnelled through here however, and as such, said requests must
now provide the appropriate target host to start with. Adjust StartTeamWindow
and TeamsWindow accordingly.
- On global init, always create an instance of the local interface.
TargetHostInterface:
- Convert to BLooper and implement TeamDebugger's Listener interface.
TargetHostInterfaces now directly manage their TeamDebugger instances,
and consequently take over the equivalent duties that the main application
previously had.
- Adjust signatures of Attach/CreateTeam to add const. Adjust
LocalTargetHostInterface accordingly.
- Add accessor to determine if a given interface is local or not. Will be
needed for the TeamDebugger's file manager eventually so it knows if it
needs to request remote files if no matching local file is found.
- Add accessor to start a TeamDebugger instance, and corresponding options
structure.
TargetHostInterfaceRoster:
- Minor adjustments to host interface initialization to take into account
needing to start the looper.
- Add accessor for number of running team debuggers, for the main app to
use when deciding to quit.
TeamDebugger:
- Add accessor for SettingsManager. Needed for the case of a restart request,
as the host interfaces do not have direct access to it.
TeamsWindow:
- For now, always grab the local host interface when initializing the window.
Once the remote interface is implemented, this will need to be adjusted, but
the appropriate UI for creating/selecting it is needed first anyways.
With these changes, the main application is fully host-agnostic, and all
management of actual debuggers is delegated to their parent host interfaces.
There still needs to be a listener interface for the host interface and/or
roster though, so that the application can be made aware of when debuggers
quit, as this drives whether it's time to terminate the app or not.
LocalTargetHostInterface:
- Implement the create and attach functionality. In theory, this completes
everything that's needed in order to adjust the main application to do
all debugger interface creation via the roster.
TargetHostInterfaceRoster:
- Provides a singleton interface to enumerate both the available interface
types, and all currently running instances. This will provide clients like
the TeamsWindow with a way to present the user with all available types,
as well as the necessary information to configure/instantiate them.
TargetHostInterfaceInfo:
- Provides an information object for each available type of interface,
including an optional description of the settings needed to configure it.
Callers can then use this to provide a configuration UI as needed, and
once complete, request a corresponding interface instance for the desired
configuration.
{Local}TargetHostInterface:
- Add Settings parameter to Init(). Adjust LocalTargetHostInterface
accordingly.
LocalTargetHostInterfaceInfo:
- Implementation of TargetHostInterfaceInfo for the local system case.
TargetHostInterface:
- Provide interface for tracking list of TeamDebuggers attached to this
particular interface instance. Will eventually replace the current
mechanism where the Debugger app tracks this directly.
LocalTargetHostInterface:
- Cleanups.
TeamsWindow:
- On startup, instantiate a LocalTargetHostInterface, and pass it
to the TeamsListView.
TeamsListView:
- Refactor building and updating the teams list to work via TargetHost
and its respective listener interface rather than the previous combination
of be_roster and manual polling.
- Style fixes.
LocalTargetHostInterface:
- When receiving team creation events, check if the team in question actually
contains a valid app image. The kernel's create notification is sent before
the team is completely initialized, and consequently if our get_team_info()
call gets in quickly enough, the images may not be loaded yet. If this
situation is detected, add the team ID to a wait list.
- If we have waiting teams, listen for new messages with a short timeout. If no
message is received within the timeout, walk our list of waiting teams and
see if they are fully initialized yet, and if so, dispatch the appropriate
event.
- Add new model class TargetHost for host-specific information such as
the running team list.
- Add new interface class TargetHostInterface and implementing subclass
LocalTargetHostInterface. Not yet complete/usable due to some as of yet
unresolved issues with the involved system APIs.
DebuggerInterface:
- Refactor into abstract base class.
- Introduce interface configuration abstract base class.
- Move existing implementation into LocalDebuggerInterface and add
corresponding configuration class.
Debugger:
- Adjust to instantiate LocalDebuggerInterface.
In and of itself no functional change, but paves the way for further
refactoring to make the debugger fully interface-agnostic (this isn't yet
the case for retrieving target system information such as the team listing,
and creating/attaching to teams).
TeamDebugger:
- Rather than instantiating the DebuggerInterface directly, we now
expect it to be given to us externally. This allows TeamDebugger
to be agnostic of where the team actually resides.
Debugger:
- Create and initialize DebuggerInterface before passing it on to
TeamDebugger.
No functional change.
As part of the refactoring that was done for app_server layer support,
the private shape_data struct was updated to derive from BReferenceable.
However, BShape's destructor was never updated to reflect this, and
consequently attempts to use a debug build of libbe would consistently
throw the user into the debugger due to BReferenceable's sanity check
against non-zero deletes that weren't on the stack.
It should be noted though that there are probably a few things that could
be factored out and/or simplified with that class in general, since e.g.
when copying its data from another shape_data instance, it uses C++ array
allocations, while when being manipulated by BShape directly, the latter
uses alloc/realloc/free.
ImageListView:
- Add columns for the respective start and end addresses of the text and data
segments of each image. Correspondingly, adjust the table model to return
the appropriate fields from the image's info. This can come in handy for
quickly determining the approximate location of an otherwise unknown memory
address, among other things.
DwarfImageDebugInfo:
- When resolving the address of a PIC function that a value was
returned by, check if the resulting address actually belongs to
the same image as the caller. If not, find the appropriate image
for the new address. Combined with the previous commits, this fixes
the issue that functions called indirectly by PLT entry that jumped
to another image entirely wouldn't be mapped back to their
corresponding FunctionDebugInfo instance, and thus would be skipped
since we couldn't determine a type to associate the return value with.
ThreadHandler:
- When stepping over a function call, ensure that we actually have a valid
value for the stepped over function address before adding a return value
info entry. While this had no visible adverse effect, it did result in
unnecessary work when creating the list of variables to display later,
since such entries would have no valid function to resolve to, and thus
had to be ignored/thrown away.
DisassemblerX86{64}:
- Fix problematic usage of udis86 that was broken during an update.
Rather than calling the appropriate udis86 function to retrieve the
operand, we were accessing it directly on the ud struct, which was
fully filled in implicitly in previous versions of the library. However,
in the updated version of udis86, the operands are only lazily decoded on
request, and as such this data was invalid, leading to us not resolving
target addresses properly. This primarily affected determining the location
of return values.
ExpressionEvaluationWindow:
- Add team listener hooks for the various thread state changes.
- Implement these to react accordingly and keep the thread/frame menus
up to date with running program changes, whether due to user interaction
in the main team window, or background activities of the debugged app.
Previously the evaluation window needed to be closed and reopened to
refresh these appropriately.
- As suggested by Ingo, add libshared.a to the architecture name map.
This allows it to be linked by its short name like other frequently
used libraries.
- Adjust all Jamfiles referencing the lib accordingly.
- In the case of certain messages that are dispatched from the
app_server with multiple target tokens (i.e. due to an attached
view that has a mouse or keyboard event mask set), we need to
strip the focus flag from the message before passing it to the
non-focus views. Fixes a bug observed via Clipdinger where the
aforementioned circumstance would result in all keyboard shortcuts
being invoked multiple times.
- Add jamfile for a build variant of libuuid.
- Adjust the build version of makebootable to link to that instead, as it would
otherwise link in the target platform's version of libuuid_kernel, which
wasn't necessarily compatible with the build platform's objects (i.e. when
building a 32-bit Haiku image on a 64-bit host OS), and would consequently
fail.