Commit Graph

25 Commits

Author SHA1 Message Date
Alessandro Arzilli
f3e76238e3
proc: move breakpoint condition evaluation out of backends (#2628)
* 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.
2021-08-09 10:16:24 -07:00
Alessandro Arzilli
658d36cb19
proc: allow multiple overlapping internal breakpoints (#2519)
Changes Breakpoint to allow multiple overlapping internal breakpoints
on the same instruction address.
This is done by changing the Breakpoint structure to contain a list of
"breaklets", each breaklet has a BreakpointKind and a condition
expression, independent of the other.
A breakpoint is considered active if any of its breaklets are active.
A breakpoint is removed when all its breaklets are removed.
We also change the terminology "internal breakpoint" to "stepping
breakpoint":

HasInternalBreakpoints -> HasSteppingBreakpoints
IsInternal -> IsStepping
etc...

The motivation for this change is implementing watchpoints on stack
variables.
Watching a stack variable requires also setting a special breakpoint to
find out when the variable goes out of scope. These breakpoints can not
be UserBreakpoints because only one user breakpoint is allowed on the
same instruction and they can not be internal breakpoints because they
should not be cleared when a next operation is completed (they should
be cleared when the variable watch is cleared).

Updates #279
2021-07-21 08:24:19 -07:00
Alessandro Arzilli
f0a32c8e1b
Go 1.17 support branch (#2451)
* proc: support new Go 1.17 panic/defer mechanism

Go 1.17 will create wrappers for deferred calls that take arguments.
Change defer reading code so that wrappers are automatically unwrapped.

Also the deferred function is called directly by runtime.gopanic, without going through runtime.callN which means that sometimes when a panic happens the stack is either:

0. deferred function call
1. deferred call wrapper
2. runtime.gopanic

or:

0. deferred function call
1. runtime.gopanic

instead of always being:

0. deferred function call
1. runtime.callN
2. runtime.gopanic

the isPanicCall check is changed accordingly.

* test: miscellaneous minor test fixes for Go 1.17

* proc: resolve inlined calls when stepping out of runtime.breakpoint

Calls to runtime.Breakpoint are inlined in Go 1.17 when inlining is
enabled, resolve inlined calls in stepInstructionOut.

* proc: add support for debugCallV2 with regabi

This change adds support for the new debug call protocol which had to
change for the new register ABI introduced in Go 1.17.

Summary of changes:
- Abstracts over the debug call version depending on the Go version
  found in the binary.
- Uses R12 instead of RAX as the debug protocol register when the binary
  is from Go 1.17 or later.
- Creates a variable directly from the DWARF entry for function
  arguments to support passing arguments however the ABI expects.
- Computes a very conservative stack frame size for the call when
  injecting a call into a Go process whose version is >=1.17.

Co-authored-by: Michael Anthony Knyszek <mknyszek@google.com>
Co-authored-by: Alessandro Arzilli <alessandro.arzilli@gmail.com>

* TeamCity: enable tests on go-tip

* goversion: version compatibility bump

* TeamCity: fix go-tip builds on macOS/arm64

Co-authored-by: Michael Anthony Knyszek <mknyszek@google.com>
2021-07-08 08:47:53 -07:00
Alessandro Arzilli
1b0c4310c4
proc: give unique addresses to registerized variables (#2527)
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.
2021-07-02 18:37:55 +02:00
Derek Parker
42ecbd4413
proc,terminal: Ensure correct exit status (#2543)
Ensure that any command executed after the process we are trying to
debug prints a correct and consistent exit status.

Previously the exit code was being lost after the first time we printed
that a process has exited. Additionally, certain commands would print
the PID of the process and other would not. This change makes everything
more correct and consistent.
2021-06-22 13:35:13 +02:00
Alessandro Arzilli
58762685e3
proc/native: low level support for watchpoints in linux/amd64 (#2301)
Adds the low-level support for watchpoints (aka data breakpoints) to
the native linux/amd64 backend.

Does not add user interface or functioning support for watchpoints
on stack variables.

Updates #279
2021-05-06 10:33:56 -07:00
Alessandro Arzilli
6a70d531bb
proc/*: implement proc.(*compositeMemory).WriteMemory (#2271)
Delve represents registerized variables (fully or partially) using
compositeMemory, implementing proc.(*compositeMemory).WriteMemory is
necessary to make SetVariable and function calls work when Go will
switch to using the register calling convention in 1.17.

This commit also makes some refactoring by moving the code that
converts between register numbers and register names out of pkg/proc
into a different package.
2021-03-04 10:28:28 -08:00
Alessandro Arzilli
807664b34b
proc: add flag to distinguish ReturnValues (#2230)
Adds a flag that distinguishes the return values of an injected
function call from the return values of a function call executed by the
target program.
2020-12-10 08:57:50 -08:00
Alessandro Arzilli
0843376018
proc/*: remove proc.Thread.Blocked, refactor memory access (#2206)
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
2020-11-09 11:28:40 -08:00
Alessandro Arzilli
12009e9833
proc/*,service: replace uses of uintptr with uint64 (#2163)
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.
2020-09-09 10:36:15 -07:00
chainhelen
e07bfd3180
pkg/proc: fix dlv panic when sameGCond is nil. (#2164)
`sameFrameCond` should not be constructed as one `And Express` when
`sameGCond` which is the first child of `BinaryExpr` is nil.

Fixes: #2162
2020-09-08 15:18:49 -07:00
aarzilli
f90134eb4d proc: prevent internal breakpoint conditions from failing
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
2020-09-01 15:01:39 +02:00
Alessandro Arzilli
f9c8f7f55b
Go 1.15 support (#2011)
* 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
2020-07-28 09:19:51 -07:00
Alessandro Arzilli
54664c54db
proc: use file:line at entry point in skipAutogeneratedWrappersOut (#2089)
The file:line information for the entrypoint is more acccurate than the
file:line information at a return point, which could be affected by a
compiler bug.

Fixes #2086
2020-07-21 13:44:04 -07:00
Alessandro Arzilli
67f6a21ab8
proc: refresh cur thread/sel g after ContineOnce errors (#2081)
On platforms other than macOS this doesn't matter but on macOS a
segmentation fault will cause ContinueOnce to return an error, before
returning it we should still fix the current thread and selected
goroutine values.

Fixes #2078
2020-06-11 11:46:00 -07:00
Alessandro Arzilli
292f5c69f0
proc: step into unexported runtime funcs when already inside runtime (#2061)
Normally we don't step into unexported runtime functions because the
compiler is free to insert them into the code and they are not relevant
to the user, however if we are already stepping through a runtime
function we should let step into work normally and step into other
runtime functions.
2020-06-05 10:29:28 -07:00
Alessandro Arzilli
80b5b95182
proc/*: move Set/Clear Breakpoint methods to Target (#2064) 2020-06-03 11:14:14 -07:00
Alessandro Arzilli
200994bc8f
proc/*: only load floating point registers when needed (#1981)
Changes implementations of proc.Registers interface and the
op.DwarfRegisters struct so that floating point registers can be loaded
only when they are needed.
Removes the floatingPoint parameter from proc.Thread.Registers.
This accomplishes three things:

1. it simplifies the proc.Thread.Registers interface
2. it makes it impossible to accidentally create a broken set of saved
   registers or of op.DwarfRegisters by accidentally calling
   Registers(false)
3. it improves general performance of Delve by avoiding to load
   floating point registers as much as possible

Floating point registers are loaded under two circumstances:

1. When the Slice method is called with floatingPoint == true
2. When the Copy method is called

Benchmark before:

BenchmarkConditionalBreakpoints-4   	       1	4327350142 ns/op

Benchmark after:

BenchmarkConditionalBreakpoints-4   	       1	3852642917 ns/op

Updates #1549
2020-05-13 11:56:50 -07:00
aarzilli
bb2525a7d5 proc: keep debugger state consistent if callInjectionProtocol fails
pickCurrentThread should always run.
2020-05-01 10:15:29 -07:00
aarzilli
ae846a51f2 proc: StepOut remove if condition that is always true 2020-04-10 10:49:19 -07:00
aarzilli
7dedf1ed55 proc: simplify next/step/stepout condition code
Adds a library of utility functions to generated breakpoint conditions
for next, step and stepout.
2020-04-04 11:00:54 -07:00
aarzilli
431dea7ee6 proc: skip autogenerated wrappers when stepping in and out
Under some circumstances (methods with non-pointer receivers or from
embedded fields called through an interface) the compiler will
autogenerate wrapper functions.

This commit changes next, step and stepout to skip all autogenerated
wrappers.

Fixes #1908
2020-03-31 10:04:36 -07:00
Alessandro Arzilli
223e0a57ca
proc: convert Arch into a struct (#1972)
Replace the interface type Arch with a struct with the same
functionality.
2020-03-30 11:03:29 -07:00
Derek Parker
5177c247f6 pkg/proc: Remove unused parameter
Also cleanup some typos.
2020-03-28 16:32:09 +01:00
Derek Parker
4abf4f1c1f pkg/proc: Rename proc.go -> target_exec.go 2020-03-25 17:45:12 +01:00