-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ability to safely call functions #119
Comments
Comment moved here from PR #331: I did think a bit about calling functions (without writing any code so this is purely philosophical) this is what I thought would be the pain points: a. panics Regarding (a), one solution is to set a breakpoint on panic and abort the evaluation as soon as it is called, before it starts unwinding the stack. This is not ideal, the panic could be recovered by a frame below our dummy frame, but given how panics are generally used by go code it should be a big deal. The other possibility would be to abort the call only when the stack unwind gets to our dummy frame, possibly modifying the Regarding (b) and (c) I have two possible solution Orthodox solutionFor (b) we disable all user breakpoints. (c) is hard: I'm not sure it's possible to suppress co-operative scheduler calls, maybe abort on them? Even pre-emptive scheduler calls may be hard because they seem to be at least in part intertwined with stack resizes (which we can not suppress). Unorthodox solutionWe call This is easier to implement because we don't have to worry about (b) and especially (c) but it's weird for the user.
The user must use a different command to enable function calls, this command will have a behaviour similar to
the function call did not complete, the user got a breakpoint somewhere else in the program, the user can interact with the debugger:
after another continue the original |
@derekparker @aarzilli Do we need some changes in Go itself for this issue? |
@ignatov: likely yes. On top of the design problems in my previous message there is also another thing to be considered. Let's say we want to initiate a call, from the debugger, to a function F from goroutine G.
|
@aarzilli maybe we should file an issue in https://github.com/golang/go/issues? We had a conversation with @rsc, and he told us that Go team is going to provide a good basement for debugger at least. |
@ignatov Did you create an issue at https://github.com/golang/go/issues ? I'm asking, since I would like to file an issue in the Go repo, if you haven't already. Especially now that Go is collecting feedback on stuff that should go into Go2, I think a better debugging experience should be of utmost importance and having an issue open with them would greatly help. |
No, I didn't. Could you please do it? |
Pardon my jumping in here, but could we side-step all the GC related issues by disabling it during the function call?
|
update: Additionally, there is a new proposal; golang/go#24543 that if adopted would |
barely working Updates go-delve#119
barely working Updates go-delve#119
barely working Updates go-delve#119
barely working Updates go-delve#119
barely working Updates go-delve#119
barely working Updates go-delve#119
This adds a mechanism for debuggers to safely inject calls to Go functions on amd64. Debuggers must participate in a protocol with the runtime, and need to know how to lay out a call frame, but the runtime support takes care of the details of handling live pointers in registers, stack growth, and detecting the trickier conditions when it is unsafe to inject a user function call. Fixes #21678. Updates derekparker/delve#119. Change-Id: I56d8ca67700f1f77e19d89e7fc92ab337b228834 Reviewed-on: https://go-review.googlesource.com/109699 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
Implements the function call injection protocol introduced in go 1.11 by https://go-review.googlesource.com/c/go/+/109699. This is only the basic support, see TODO comments in pkg/proc/fncall.go for a list of missing features. Updates go-delve#119
Implements the function call injection protocol introduced in go 1.11 by https://go-review.googlesource.com/c/go/+/109699. This is only the basic support, see TODO comments in pkg/proc/fncall.go for a list of missing features. Updates go-delve#119
Implements the function call injection protocol introduced in go 1.11 by https://go-review.googlesource.com/c/go/+/109699. This is only the basic support, see TODO comments in pkg/proc/fncall.go for a list of missing features. Updates go-delve#119
Implements the function call injection protocol introduced in go 1.11 by https://go-review.googlesource.com/c/go/+/109699. This is only the basic support, see TODO comments in pkg/proc/fncall.go for a list of missing features. Updates go-delve#119
Implements the function call injection protocol introduced in go 1.11 by https://go-review.googlesource.com/c/go/+/109699. This is only the basic support, see TODO comments in pkg/proc/fncall.go for a list of missing features. Updates go-delve#119
Implements the function call injection protocol introduced in go 1.11 by https://go-review.googlesource.com/c/go/+/109699. This is only the basic support, see TODO comments in pkg/proc/fncall.go for a list of missing features. Updates go-delve#119
Implements the function call injection protocol introduced in go 1.11 by https://go-review.googlesource.com/c/go/+/109699. This is only the basic support, see TODO comments in pkg/proc/fncall.go for a list of missing features. Updates go-delve#119
Implements the function call injection protocol introduced in go 1.11 by https://go-review.googlesource.com/c/go/+/109699. This is only the basic support, see TODO comments in pkg/proc/fncall.go for a list of missing features. Updates go-delve#119
Implements the function call injection protocol introduced in go 1.11 by https://go-review.googlesource.com/c/go/+/109699. This is only the basic support, see TODO comments in pkg/proc/fncall.go for a list of missing features. Updates #119
I am implementing IDE integration with delve. It would be helpful to have an option to disable breakpoints while a function call is executed (as @aarzilli mentioned). Are there any plans regarding this? |
The initial implementation of the 'call' command required the function call to be the root expression, i.e. something like: double(3) + 1 was not allowed, because the root expression was the binary operator '+', not the function call. With this change expressions like the one above and others are allowed. This is the first step necessary to implement nested function calls (where the result of a function call is used as argument to another function call). This is implemented by replacing proc.CallFunction with proc.EvalExpressionWithCalls. EvalExpressionWithCalls will run proc.(*EvalScope).EvalExpression in a different goroutine. This goroutine, the 'eval' goroutine, will communicate with the main goroutine of the debugger by means of two channels: continueRequest and continueCompleted. The eval goroutine evaluates the expression recursively, when a function call is encountered it takes care of setting up the function call on the target program and writes a request to the continueRequest channel, this causes the 'main' goroutine to restart the target program by calling proc.Continue. Whenever Continue encounters a breakpoint that belongs to the function call injection protocol (runtime.debugCallV1 and associated functions) it writes to continueCompleted which resumes the 'eval' goroutine. The 'eval' goroutine takes care of implementing the function call injection protocol. When the expression is fully evaluated the 'eval' goroutine will write a special message to 'continueRequest' signaling that the expression evaluation is terminated which will cause Continue to return to the user. Updates go-delve#119
Changes the code in fncall.go to support nested function calls. This changes delays argument evaluation until after we have used the call injection protocol to allocate an argument frame. When evaluating the parse tree of an expression we'll initiate each function call we find on the way down and then complete the function call on the way up. For example. in: f(g(x)) we will: 1. initiate the call injection protocol for f(...) 2. progress it until the point where we have space for the arguments of 'f' (i.e. when we receive the debugCallAXCompleteCall message from the target runtime) 3. inititate the call injection protocol for g(...) 4. progress it until the point where we have space for the arguments of 'g' 5. copy the value of x into the argument frame of 'g' 6. finish the call to g(...) 7. copy the return value of g(x) into the argument frame of 'f' 8. finish the call to f(...) Updates go-delve#119
The initial implementation of the 'call' command required the function call to be the root expression, i.e. something like: double(3) + 1 was not allowed, because the root expression was the binary operator '+', not the function call. With this change expressions like the one above and others are allowed. This is the first step necessary to implement nested function calls (where the result of a function call is used as argument to another function call). This is implemented by replacing proc.CallFunction with proc.EvalExpressionWithCalls. EvalExpressionWithCalls will run proc.(*EvalScope).EvalExpression in a different goroutine. This goroutine, the 'eval' goroutine, will communicate with the main goroutine of the debugger by means of two channels: continueRequest and continueCompleted. The eval goroutine evaluates the expression recursively, when a function call is encountered it takes care of setting up the function call on the target program and writes a request to the continueRequest channel, this causes the 'main' goroutine to restart the target program by calling proc.Continue. Whenever Continue encounters a breakpoint that belongs to the function call injection protocol (runtime.debugCallV1 and associated functions) it writes to continueCompleted which resumes the 'eval' goroutine. The 'eval' goroutine takes care of implementing the function call injection protocol. When the expression is fully evaluated the 'eval' goroutine will write a special message to 'continueRequest' signaling that the expression evaluation is terminated which will cause Continue to return to the user. Updates go-delve#119
Changes the code in fncall.go to support nested function calls. This changes delays argument evaluation until after we have used the call injection protocol to allocate an argument frame. When evaluating the parse tree of an expression we'll initiate each function call we find on the way down and then complete the function call on the way up. For example. in: f(g(x)) we will: 1. initiate the call injection protocol for f(...) 2. progress it until the point where we have space for the arguments of 'f' (i.e. when we receive the debugCallAXCompleteCall message from the target runtime) 3. inititate the call injection protocol for g(...) 4. progress it until the point where we have space for the arguments of 'g' 5. copy the value of x into the argument frame of 'g' 6. finish the call to g(...) 7. copy the return value of g(x) into the argument frame of 'f' 8. finish the call to f(...) Updates go-delve#119
Given that https://go-review.googlesource.com/c/go/+/109699/ is merged into go 1.12, which has been released, does there now exist a reasonable estimate when this feature will be ready? |
@coriolinus this feature is already implemented in the latest release of Delve, however it has been left open as there are still some improvements to be made. |
That's excellent to know, thanks!
…On Thu, Mar 7, 2019 at 6:29 PM Derek Parker ***@***.***> wrote:
@coriolinus <https://github.com/coriolinus> this feature is already
implemented in the latest release of Delve, however it has been left open
as there are still some improvements to be made.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#119 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AHdeTnM3kaO_e8ChiWlkH-OH9xiGqyHFks5vUUyFgaJpZM4EOwJX>
.
|
The initial implementation of the 'call' command required the function call to be the root expression, i.e. something like: double(3) + 1 was not allowed, because the root expression was the binary operator '+', not the function call. With this change expressions like the one above and others are allowed. This is the first step necessary to implement nested function calls (where the result of a function call is used as argument to another function call). This is implemented by replacing proc.CallFunction with proc.EvalExpressionWithCalls. EvalExpressionWithCalls will run proc.(*EvalScope).EvalExpression in a different goroutine. This goroutine, the 'eval' goroutine, will communicate with the main goroutine of the debugger by means of two channels: continueRequest and continueCompleted. The eval goroutine evaluates the expression recursively, when a function call is encountered it takes care of setting up the function call on the target program and writes a request to the continueRequest channel, this causes the 'main' goroutine to restart the target program by calling proc.Continue. Whenever Continue encounters a breakpoint that belongs to the function call injection protocol (runtime.debugCallV1 and associated functions) it writes to continueCompleted which resumes the 'eval' goroutine. The 'eval' goroutine takes care of implementing the function call injection protocol. When the expression is fully evaluated the 'eval' goroutine will write a special message to 'continueRequest' signaling that the expression evaluation is terminated which will cause Continue to return to the user. Updates go-delve#119
Changes the code in fncall.go to support nested function calls. This changes delays argument evaluation until after we have used the call injection protocol to allocate an argument frame. When evaluating the parse tree of an expression we'll initiate each function call we find on the way down and then complete the function call on the way up. For example. in: f(g(x)) we will: 1. initiate the call injection protocol for f(...) 2. progress it until the point where we have space for the arguments of 'f' (i.e. when we receive the debugCallAXCompleteCall message from the target runtime) 3. inititate the call injection protocol for g(...) 4. progress it until the point where we have space for the arguments of 'g' 5. copy the value of x into the argument frame of 'g' 6. finish the call to g(...) 7. copy the return value of g(x) into the argument frame of 'f' 8. finish the call to f(...) Updates go-delve#119
The initial implementation of the 'call' command required the function call to be the root expression, i.e. something like: double(3) + 1 was not allowed, because the root expression was the binary operator '+', not the function call. With this change expressions like the one above and others are allowed. This is the first step necessary to implement nested function calls (where the result of a function call is used as argument to another function call). This is implemented by replacing proc.CallFunction with proc.EvalExpressionWithCalls. EvalExpressionWithCalls will run proc.(*EvalScope).EvalExpression in a different goroutine. This goroutine, the 'eval' goroutine, will communicate with the main goroutine of the debugger by means of two channels: continueRequest and continueCompleted. The eval goroutine evaluates the expression recursively, when a function call is encountered it takes care of setting up the function call on the target program and writes a request to the continueRequest channel, this causes the 'main' goroutine to restart the target program by calling proc.Continue. Whenever Continue encounters a breakpoint that belongs to the function call injection protocol (runtime.debugCallV1 and associated functions) it writes to continueCompleted which resumes the 'eval' goroutine. The 'eval' goroutine takes care of implementing the function call injection protocol. When the expression is fully evaluated the 'eval' goroutine will write a special message to 'continueRequest' signaling that the expression evaluation is terminated which will cause Continue to return to the user. Updates go-delve#119
Changes the code in fncall.go to support nested function calls. This changes delays argument evaluation until after we have used the call injection protocol to allocate an argument frame. When evaluating the parse tree of an expression we'll initiate each function call we find on the way down and then complete the function call on the way up. For example. in: f(g(x)) we will: 1. initiate the call injection protocol for f(...) 2. progress it until the point where we have space for the arguments of 'f' (i.e. when we receive the debugCallAXCompleteCall message from the target runtime) 3. inititate the call injection protocol for g(...) 4. progress it until the point where we have space for the arguments of 'g' 5. copy the value of x into the argument frame of 'g' 6. finish the call to g(...) 7. copy the return value of g(x) into the argument frame of 'f' 8. finish the call to f(...) Updates go-delve#119
The initial implementation of the 'call' command required the function call to be the root expression, i.e. something like: double(3) + 1 was not allowed, because the root expression was the binary operator '+', not the function call. With this change expressions like the one above and others are allowed. This is the first step necessary to implement nested function calls (where the result of a function call is used as argument to another function call). This is implemented by replacing proc.CallFunction with proc.EvalExpressionWithCalls. EvalExpressionWithCalls will run proc.(*EvalScope).EvalExpression in a different goroutine. This goroutine, the 'eval' goroutine, will communicate with the main goroutine of the debugger by means of two channels: continueRequest and continueCompleted. The eval goroutine evaluates the expression recursively, when a function call is encountered it takes care of setting up the function call on the target program and writes a request to the continueRequest channel, this causes the 'main' goroutine to restart the target program by calling proc.Continue. Whenever Continue encounters a breakpoint that belongs to the function call injection protocol (runtime.debugCallV1 and associated functions) it writes to continueCompleted which resumes the 'eval' goroutine. The 'eval' goroutine takes care of implementing the function call injection protocol. When the expression is fully evaluated the 'eval' goroutine will write a special message to 'continueRequest' signaling that the expression evaluation is terminated which will cause Continue to return to the user. Updates go-delve#119
The initial implementation of the 'call' command required the function call to be the root expression, i.e. something like: double(3) + 1 was not allowed, because the root expression was the binary operator '+', not the function call. With this change expressions like the one above and others are allowed. This is the first step necessary to implement nested function calls (where the result of a function call is used as argument to another function call). This is implemented by replacing proc.CallFunction with proc.EvalExpressionWithCalls. EvalExpressionWithCalls will run proc.(*EvalScope).EvalExpression in a different goroutine. This goroutine, the 'eval' goroutine, will communicate with the main goroutine of the debugger by means of two channels: continueRequest and continueCompleted. The eval goroutine evaluates the expression recursively, when a function call is encountered it takes care of setting up the function call on the target program and writes a request to the continueRequest channel, this causes the 'main' goroutine to restart the target program by calling proc.Continue. Whenever Continue encounters a breakpoint that belongs to the function call injection protocol (runtime.debugCallV1 and associated functions) it writes to continueCompleted which resumes the 'eval' goroutine. The 'eval' goroutine takes care of implementing the function call injection protocol. When the expression is fully evaluated the 'eval' goroutine will write a special message to 'continueRequest' signaling that the expression evaluation is terminated which will cause Continue to return to the user. Updates #119
Changes the code in fncall.go to support nested function calls. This changes delays argument evaluation until after we have used the call injection protocol to allocate an argument frame. When evaluating the parse tree of an expression we'll initiate each function call we find on the way down and then complete the function call on the way up. For example. in: f(g(x)) we will: 1. initiate the call injection protocol for f(...) 2. progress it until the point where we have space for the arguments of 'f' (i.e. when we receive the debugCallAXCompleteCall message from the target runtime) 3. inititate the call injection protocol for g(...) 4. progress it until the point where we have space for the arguments of 'g' 5. copy the value of x into the argument frame of 'g' 6. finish the call to g(...) 7. copy the return value of g(x) into the argument frame of 'f' 8. finish the call to f(...) Updates go-delve#119
* proc: support nested function calls Changes the code in fncall.go to support nested function calls. This changes delays argument evaluation until after we have used the call injection protocol to allocate an argument frame. When evaluating the parse tree of an expression we'll initiate each function call we find on the way down and then complete the function call on the way up. For example. in: f(g(x)) we will: 1. initiate the call injection protocol for f(...) 2. progress it until the point where we have space for the arguments of 'f' (i.e. when we receive the debugCallAXCompleteCall message from the target runtime) 3. inititate the call injection protocol for g(...) 4. progress it until the point where we have space for the arguments of 'g' 5. copy the value of x into the argument frame of 'g' 6. finish the call to g(...) 7. copy the return value of g(x) into the argument frame of 'f' 8. finish the call to f(...) Updates #119 * proc: bugfix: closure addr was wrong for non-closure functions
Going to officially close this out as we now have this functionality. We will continue adding more improvements and @aarzilli has done a ton already. |
go-delve#119) * added dev env container for webhook worker * using ContainerName * Squashed commit of the following: commit 504164e Author: Elliot <elliot@burstsms.com> Date: Thu Jan 28 16:23:29 2021 +1100 RPC infra simplification (go-delve#118) * init * mm7 port * rpcbuilder listen host * container names fix for jaeger * revert port mapping in dev * template * container_port, container_name struct fields * rpc_service -> rpc_address env vars/ struct fields * charts * trigger build rerun * struct fields * more fields and naming * removed extra blank line * de-lint * changing the webhook message queue exchange name to "webhook-post" * remove ports not required until the health check PR is created
Implements the function call injection protocol introduced in go 1.11 by https://go-review.googlesource.com/c/go/+/109699. This is only the basic support, see TODO comments in pkg/proc/fncall.go for a list of missing features. Updates go-delve#119
) The initial implementation of the 'call' command required the function call to be the root expression, i.e. something like: double(3) + 1 was not allowed, because the root expression was the binary operator '+', not the function call. With this change expressions like the one above and others are allowed. This is the first step necessary to implement nested function calls (where the result of a function call is used as argument to another function call). This is implemented by replacing proc.CallFunction with proc.EvalExpressionWithCalls. EvalExpressionWithCalls will run proc.(*EvalScope).EvalExpression in a different goroutine. This goroutine, the 'eval' goroutine, will communicate with the main goroutine of the debugger by means of two channels: continueRequest and continueCompleted. The eval goroutine evaluates the expression recursively, when a function call is encountered it takes care of setting up the function call on the target program and writes a request to the continueRequest channel, this causes the 'main' goroutine to restart the target program by calling proc.Continue. Whenever Continue encounters a breakpoint that belongs to the function call injection protocol (runtime.debugCallV1 and associated functions) it writes to continueCompleted which resumes the 'eval' goroutine. The 'eval' goroutine takes care of implementing the function call injection protocol. When the expression is fully evaluated the 'eval' goroutine will write a special message to 'continueRequest' signaling that the expression evaluation is terminated which will cause Continue to return to the user. Updates go-delve#119
* proc: support nested function calls Changes the code in fncall.go to support nested function calls. This changes delays argument evaluation until after we have used the call injection protocol to allocate an argument frame. When evaluating the parse tree of an expression we'll initiate each function call we find on the way down and then complete the function call on the way up. For example. in: f(g(x)) we will: 1. initiate the call injection protocol for f(...) 2. progress it until the point where we have space for the arguments of 'f' (i.e. when we receive the debugCallAXCompleteCall message from the target runtime) 3. inititate the call injection protocol for g(...) 4. progress it until the point where we have space for the arguments of 'g' 5. copy the value of x into the argument frame of 'g' 6. finish the call to g(...) 7. copy the return value of g(x) into the argument frame of 'f' 8. finish the call to f(...) Updates go-delve#119 * proc: bugfix: closure addr was wrong for non-closure functions
Implements the function call injection protocol introduced in go 1.11 by https://go-review.googlesource.com/c/go/+/109699. This is only the basic support, see TODO comments in pkg/proc/fncall.go for a list of missing features. Updates go-delve#119
) The initial implementation of the 'call' command required the function call to be the root expression, i.e. something like: double(3) + 1 was not allowed, because the root expression was the binary operator '+', not the function call. With this change expressions like the one above and others are allowed. This is the first step necessary to implement nested function calls (where the result of a function call is used as argument to another function call). This is implemented by replacing proc.CallFunction with proc.EvalExpressionWithCalls. EvalExpressionWithCalls will run proc.(*EvalScope).EvalExpression in a different goroutine. This goroutine, the 'eval' goroutine, will communicate with the main goroutine of the debugger by means of two channels: continueRequest and continueCompleted. The eval goroutine evaluates the expression recursively, when a function call is encountered it takes care of setting up the function call on the target program and writes a request to the continueRequest channel, this causes the 'main' goroutine to restart the target program by calling proc.Continue. Whenever Continue encounters a breakpoint that belongs to the function call injection protocol (runtime.debugCallV1 and associated functions) it writes to continueCompleted which resumes the 'eval' goroutine. The 'eval' goroutine takes care of implementing the function call injection protocol. When the expression is fully evaluated the 'eval' goroutine will write a special message to 'continueRequest' signaling that the expression evaluation is terminated which will cause Continue to return to the user. Updates go-delve#119
* proc: support nested function calls Changes the code in fncall.go to support nested function calls. This changes delays argument evaluation until after we have used the call injection protocol to allocate an argument frame. When evaluating the parse tree of an expression we'll initiate each function call we find on the way down and then complete the function call on the way up. For example. in: f(g(x)) we will: 1. initiate the call injection protocol for f(...) 2. progress it until the point where we have space for the arguments of 'f' (i.e. when we receive the debugCallAXCompleteCall message from the target runtime) 3. inititate the call injection protocol for g(...) 4. progress it until the point where we have space for the arguments of 'g' 5. copy the value of x into the argument frame of 'g' 6. finish the call to g(...) 7. copy the return value of g(x) into the argument frame of 'f' 8. finish the call to f(...) Updates go-delve#119 * proc: bugfix: closure addr was wrong for non-closure functions
Add support for calling functions within the current scope. Should allow specifying in-scope variables as arguments to these function calls.
call myFunc(localVar, 4, "foo")
The text was updated successfully, but these errors were encountered: