We have used a goroutine to keep track of some of the expression
evaluation status across target resumes during call injections.
Now that the expression interpreter has been rewritten to use a stack
machine we can move what little state is left into the stack machine
and get rid of the goroutine-and-channel mechanism.
* proc: use stack machine to evaluate expressions
This commit splits expression evaluation into two parts. The first part (in
pkg/proc/evalop/evalcompile.go) "compiles" as ast.Expr into a list of
instructions (defined in pkg/proc/evalop/ops.go) for a stack machine
(defined by `proc.(*evalStack)`).
The second part is a stack machine (implemented by `proc.(*EvalScope).eval`
and `proc.(*EvalScope).evalOne`) that has two modes of operation: in the
main mode it executes inteructions from the list (by calling `evalOne`), in
the second mode it executes the call injection protocol by calling
`funcCallStep` repeatedly until it either the protocol finishes, needs more
input from the stack machine (to set call arguments) or fails.
This approach has several benefits:
- it is now possible to remove the goroutine we use to evaluate expression
and the channel used to communicate with the Continue loop.
- every time we resume the target to execute the call injection protocol we
need to update several local variables to match the changed state of the
target, this is now done at the top level of the evaluation loop instead of
being hidden inside a recurisive evaluator
- using runtime.Pin to pin addresses returned by an injected call would
allow us to use a more natural evaluation order for function calls, which
would solve some bugs #3310, allow users to inspect values returned by a
call injection #1599 and allow implementing some other features #1465. Doing
this with the recursive evaluator, while keeping backwards compatibility
with versions of Go that do not have runtime.Pin is very hard. However after
this change we can simply conditionally change how compileFunctionCall works
and add some opcodes.
* review round 1
* review round 2
* proc: correctly update local variables after continue
At various point during the execution of the call injection protocol
the process is resumed and the call injection goroutine could migrate
to a different thread, we must make sure to update our local variables
correctly after every point where the target program is resumed.
'fncall122debug_clean' on 'f469a0a5'.
* go.mod: update golang.org/x/tools
Go 1.22 broke golang.org/x/tools/packages
* cmd/dlv: disable TestStaticcheck with go1.22
Go 1.22 is not yet supported by staticcheck.
Adds -chan option to the goroutines command to list only the goroutines
running on a specified channel.
Also when printing a variable if it is a channel also print the list of
goroutines that are waiting on it.
If there is no current goroutine when 'next', 'step' or 'stepout' are
used set a condition that the thread ID should stay the same instead.
This makes stepping work for multithreaded C programs or Go programs
that have threads started by cgo code.
Fixes#3262
* logflags,proc: flag to log stacktrace execution
Add a log flag to write logs about what the stacktracer does.
* proc: read context from sigtrampgo, fixes TestCgoStacktrace2 on 1.21
Changes stacktrace code to read the signal context from the arguments
of sigtrampgo.
Also changes the automatic fatalthrow breakpoint for go 1.21.
In combination these two changes fix TestCgoStacktrace2 on Go 1.21 on
various platforms.
The compiler produces ABI compatibility wrappers for some functions.
We have changed the support for breakpoints to allow a single logical
breakpoint to correspond to multiple physical breakpoints, take
advantage of that to set breakpoints on both the ABI wrapper and the
real function.
Fixes#3296
This patch changes how we handle end_seq in the debug_line state machine
program. Instead of always considering the state machine invalid at the
end_seq instead simply consider the *current* address invalid. This
solves a number of issues such as incorrect disassemble output for the
last few instructions in certain functions, and creating an eval scope
at an address within the last few instructions of certain functions. It
also handles the case where the end_seq address is the same as the start
address of the next adjacent function, which would previously confuse
Delve which is why we initially marked end_seq as invalid for the entire
state machine. This approach is more nuanced and still solves that
initial problem while fixing some problems introduced by that patch.
Fixes a bug where we cannot get locals (including arguments and return
values) from a given scope because the line number state machine ends up
in an invalid state because of this parameter being set to false.
* proc: add a test for dangling unsafe pointers
This new tests checks the behavior when dereferencing dangling pointers.
The behavior does not fully make sense; the test checks the current
behavior for now, which will be improved in subsequent commits.
* proc: populate pointer values
This patch changes how Value and Unreadable are populated for pointer
Variables. Before this patch, variables of kind reflect.Ptr did not have
their Value field populated. This patch populates it in
Variable.loadValue(), which seems natural and consistent with other
types of variables. The Value is the address that the pointer points to.
The Unreadable field was populated inconsistently for pointer variables:
it was never populated for an outer pointer, but it could be populated
for an inner pointer in pointer-to-pointer types. Before this patch,
in pointer whose value could not be read was not easily distinguishable
from a pointer with a value that could be read, but that cannot be
dereferenced (i.e. a dangling pointer): neither of these would be marked
as Unreadable, and both would have a child marked as Unreadable. This
patch makes it so that a pointer variable whose pointer value cannot be
read is marked as Unreadable.
Using this new distinction, this patch fixes a bug around dereferencing
dangling pointers: before, attempting such a dereference produced a
"nil pointer dereference" error. This was bogus, since the pointer was
not nil. Now, we are more discerning and generate a different error.
* proc: allow casts form unsafe.Pointer to any pointer and vice versa
We've allowed doing this with uintptr but we should allow
unsafe.Pointer to be used like Go uses it.
* proc: fix type casts to ptr-to-ptr types
Fix type casts to **type.
Go 1.20 switched to uint64 to represent goroutine IDs, we can't
actually follow suit because we have allowed clients to use -1 to refer
to the currently selected goroutine, however we should at least switch
to int64 and also update the rtype check to accept the 1.20 type.
We allowed integer and pointer type casts everywhere but type casts to
string, []byte and []rune only at toplevel.
Fuse evalToplevelTypeCast and evalTypeCast and allow both kinds
everywhere. There are multiple other ways to create variables than
don't reference user memory anyway (which wasn't the case back when
evalToplevelTypeCast was implemented).
Fixes#1423
When doing a map lookup with a string literal we should load as much of
the keys to at least match the length of the string literal, so that
the lookup doesn't fail with the "string too long" error.
Fixes#3034
Go 1.19 also formats doc comments according to the new godoc syntax.
Some of our comments, especially unexported symbols did not conform to
the godoc syntax and therefore are mangled by 'go fmt'.
This PR runs 'go fmt' from go1.19 on everything and manually fixes the
problems.
See also:
https://github.com/golang/proposal/blob/master/design/51082-godocfmt.md
* made Pid a method of Target instead of a method of Process
* changed argument of NewTarget to ProcessInternal, since that's the
interface that backends have to implement
* removed warnings about ProcessInternal since there is no way for
users of pkg/proc to access those methods anyway
* made RecordingManipulation an optional interface for backends, Target
supplies its own dummy implementation when the backend doesn't
* inlined small interfaces that only existed to be inlined in
proc.Process anyway
* removed unused function findExecutable in the Windows and no-native
darwin backends
* removed (*EvalScope).EvalVariable, an old synonym for EvalExpression
* proc,locspec: support setting breakpoints by func name on generic funcs
Changes proc.Function to parse function names correctly when they
contain instantiation lists and locspec to match generic functions.
* vendor: update golang.org/x/tools
The old version of golang.org/x/tools is incompatible with the new
iexport format.
Change debug_info type reader and proc to convert parametric types into
their real types by reading the corresponding dictionary entry and
using the same method used for interfaces to retrieve the DIE from a
runtime._type address.
'2586e9b1'.
When the function we are calling is an autogenerated stub (because, for
example, we are calling it through a function pointer) the declaration
line of variables is meaningless and could cause us to discard valid
return arguments.
* proc: move breakpoint condition evaluation out of backends
Moves breakpoint condition evaluation from the point where breakpoints
are set, inside ContinueOnce, to (*Target).Continue.
This accomplishes three things:
1. the breakpoint evaluation method needs not be exported anymore
2. breakpoint condition evaluation can be done with a full scope,
containing a Target object, something that wasn't possible before
because ContinueOnce doesn't have access to the Target object.
3. moves breakpoint condition evaluation out of the critical section
where some of the threads of the target process might be still
running.
* proc/native: handle process death during stop() on Windows
It is possible that the thread dies while we are inside the stop()
function. This results in an Access is denied error being returned by
SuspendThread being called on threads that no longer exist.
Delay the reporting the error from SuspendThread until the end of
stop() and only report it if the thread still exists at that point.
Fixes flakyness with TestIssue1101 that was exacerbated by moving
breakpoint condition evaluation outside of the backends.
ConvertEvalScope() attempts to find the scope for the specified
goroutine id and frame index. If the goroutine that is found is nil,
then it falls back to the threads stack trace to find the scope.
This fix makes sure that the frame id is taken into account for
thread strack traces as well.
We told clients that further loading of variables can be done by
specifying a type cast using the address of a variable that we
returned.
This does not work for registerized variables (or, in general,
variables that have a complex location expression) because we don't
give them unique addresses and we throw away the compositeMemory object
we made to read them.
This commit changes proc so that:
1. variables with location expression divided in pieces do get a unique
memory address
2. the compositeMemory object is saved somewhere
3. when an integer is cast back into a pointer type we look through our
saved compositeMemory objects to see if there is one that covers the
specified address and use it.
The unique memory addresses we generate have the MSB set to 1, as
specified by the Intel 86x64 manual addresses in this form are reserved
for kernel memory (which we can not read anyway) so we are guaranteed
to never generate a fake memory address that overlaps a real memory
address of the application.
The unfortunate side effect of this is that it will break clients that
do not deserialize the address to a 64bit integer. This practice is
contrary to how we defined our types and contrary to the specification
of the JSON format, as of json.org, however it is also fairly common,
due to javascript itself having only 53bit integers.
We could come up with a new mechanism but then even more old clients
would have to be changed.
If the client supports paging, we allow them to fetch array and slice items in chunks that we assume will be of a reasonable size. For example, VS Code requests indexed variables in chunks of 100.
Fixesgolang/vscode-go#1518
Truncates the result of binary operations on integers to the size of
the resulting type.
Also rewrites convertInt to not require allocations.
Fixes#2454
Changes the expression evaluation code so that register names, when not
shadowed by local or global variables, will evaluate to the current
value of the corresponding CPU register.
This allows a greater flexibility with displaying CPU registers than is
possible with using the ListRegisters API call. Also it allows
debuggers users to view register values even if the frontend they are
using does not implement a register view.
Both structMember and findMethod implemented a depth-first search in
embedded fields but the Go specification requires a breadth-first
search. They also allowed promotion of fields in the concrete type of
embedded interfaces even though this is not allowed by Go.
Furthermore they both lacked protection from infinite recursion
when a type embeds itself and the user requests a non-existent field.
Fixes#2316
On linux we can not read memory if the thread we use to do it is
occupied doing certain system calls. The exact conditions when this
happens have never been clear.
This problem was worked around by using the Blocked method which
recognized the most common circumstances where this would happen.
However this is a hack: Blocked returning true doesn't mean that the
problem will manifest and Blocked returning false doesn't necessarily
mean the problem will not manifest. A side effect of this is issue
#2151 where sometimes we can't read the memory of a thread and find its
associated goroutine.
This commit fixes this problem by always reading memory using a thread
we know to be good for this, specifically the one returned by
ContinueOnce. In particular the changes are as follows:
1. Remove (ProcessInternal).CurrentThread and
(ProcessInternal).SetCurrentThread, the "current thread" becomes a
field of Target, CurrentThread becomes a (*Target) method and
(*Target).SwitchThread basically just sets a field Target.
2. The backends keep track of their own internal idea of what the
current thread is, to use it to read memory, this is the thread they
return from ContinueOnce as trapthread
3. The current thread in the backend and the current thread in Target
only ever get synchronized in two places: when the backend creates a
Target object the currentThread field of Target is initialized with the
backend's current thread and when (*Target).Restart gets called (when a
recording is rewound the currentThread used by Target might not exist
anymore).
4. We remove the MemoryReadWriter interface embedded in Thread and
instead add a Memory method to Process that returns a MemoryReadWriter.
The backends will return something here that will read memory using
the current thread saved by the backend.
5. The Thread.Blocked method is removed
One possible problem with this change is processes that have threads
with different memory maps. As far as I can determine this could happen
on old versions of linux but this option was removed in linux 2.5.
Fixes#2151
* proc: use argument position for addr only when injecting function calls
We can not, in general, use the argument position to determine the
address of a formal parameter, it will not work in presence of
optimizations or inlining. In those cases formal arguments could be
stored in registers.
Fixes#2176
* Travis-CI: add ignorechecksum option to chocolatey command
Looks like a configuration problem on chocolatey's end.
Co-authored-by: a <a@kra>
Since proc is supposed to work independently from the target
architecture it shouldn't use architecture-dependent types, like
uintptr. For example when reading a 64bit core file on a 32bit
architecture, uintptr will be 32bit but the addresses proc needs to
represent will be 64bit.
An internal breakpoint condition shouldn't ever error:
* use a ThreadContext to evaluate conditions if a goroutine isn't
available
* evaluate runtime.curg to a fake g variable containing only
`goid == 0` when there is no current goroutine
Fixes#2113
* proc: start variable visibility one line after their decl line
In most cases variables shouldn't be visible on their declaration line
because they won't be initialized there.
Function arguments are treated as an exception.
This fix is only applied to programs compiled with Go 1.15 or later as
previous versions of Go did not report the correct declaration line for
variables captured by closures.
Fixes#1134
* proc: silence go vet error
* Makefile: enable PIE tests on windows/Go 1.15
* core: support core files for PIEs on windows
* goversion: add Go 1.15 to supported versions
* proc: fix function call injection for Go 1.15
Go 1.15 changed the call injection protocol so that the runtime will
execute the injected call on a different (new) goroutine.
This commit changes the function call support in delve to:
1. correctly track down the call injection state after the runtime
switches to a different goroutine.
2. correctly perform the escapeCheck when stack values can come from
multiple goroutine stacks.
* proc: miscellaneous fixed for call injection under macOS with go 1.15
- create copy of SP in debugCallAXCompleteCall case because the code
used to assume that regs doesn't change
- fix automatic address calculation for function arguments when an
argument has a spurious DW_OP_piece at entry