proc: do not check return args when loading return vals of call injection
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.
This commit is contained in:
parent
de322cd113
commit
4a004e4bc1
@ -23,6 +23,7 @@ const (
|
|||||||
VariablesOnlyVisible VariablesFlags = 1 << iota
|
VariablesOnlyVisible VariablesFlags = 1 << iota
|
||||||
VariablesSkipInlinedSubroutines
|
VariablesSkipInlinedSubroutines
|
||||||
VariablesTrustDeclLine
|
VariablesTrustDeclLine
|
||||||
|
VariablesNoDeclLineCheck
|
||||||
)
|
)
|
||||||
|
|
||||||
// Variables returns a list of variables contained inside 'root'.
|
// Variables returns a list of variables contained inside 'root'.
|
||||||
@ -60,7 +61,7 @@ func variablesInternal(v []Variable, root *godwarf.Tree, depth int, pc uint64, l
|
|||||||
// are defined.
|
// are defined.
|
||||||
o = 1
|
o = 1
|
||||||
}
|
}
|
||||||
if declLine, ok := root.Val(dwarf.AttrDeclLine).(int64); !ok || line >= int(declLine)+o {
|
if declLine, ok := root.Val(dwarf.AttrDeclLine).(int64); (flags&VariablesNoDeclLineCheck != 0) || !ok || line >= int(declLine)+o {
|
||||||
return append(v, Variable{root, depth})
|
return append(v, Variable{root, depth})
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
|
|||||||
@ -899,7 +899,7 @@ func (rbpi *returnBreakpointInfo) Collect(t *Target, thread Thread) []*Variable
|
|||||||
return returnInfoError("could not read function entry", err, thread.ProcessMemory())
|
return returnInfoError("could not read function entry", err, thread.ProcessMemory())
|
||||||
}
|
}
|
||||||
|
|
||||||
vars, err := scope.Locals()
|
vars, err := scope.Locals(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return returnInfoError("could not evaluate return variables", err, thread.ProcessMemory())
|
return returnInfoError("could not evaluate return variables", err, thread.ProcessMemory())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,13 +49,21 @@ type EvalScope struct {
|
|||||||
// The goroutine executing the expression evaluation shall signal that the
|
// The goroutine executing the expression evaluation shall signal that the
|
||||||
// evaluation is complete by closing the continueRequest channel.
|
// evaluation is complete by closing the continueRequest channel.
|
||||||
callCtx *callContext
|
callCtx *callContext
|
||||||
|
|
||||||
// If trustArgOrder is true function arguments that don't have an address
|
|
||||||
// will have one assigned by looking at their position in the argument
|
|
||||||
// list.
|
|
||||||
trustArgOrder bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type localsFlags uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// If localsTrustArgOrder is set function arguments that don't have an
|
||||||
|
// address will have one assigned by looking at their position in the argument
|
||||||
|
// list.
|
||||||
|
localsTrustArgOrder localsFlags = 1 << iota
|
||||||
|
|
||||||
|
// If localsNoDeclLineCheck the declaration line isn't checked at
|
||||||
|
// all to determine if the variable is in scope.
|
||||||
|
localsNoDeclLineCheck
|
||||||
|
)
|
||||||
|
|
||||||
// ConvertEvalScope returns a new EvalScope in the context of the
|
// ConvertEvalScope returns a new EvalScope in the context of the
|
||||||
// specified goroutine ID and stack frame.
|
// specified goroutine ID and stack frame.
|
||||||
// If deferCall is > 0 the eval scope will be relative to the specified deferred call.
|
// If deferCall is > 0 the eval scope will be relative to the specified deferred call.
|
||||||
@ -201,12 +209,12 @@ func isAssignment(err error) (int, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Locals returns all variables in 'scope'.
|
// Locals returns all variables in 'scope'.
|
||||||
func (scope *EvalScope) Locals() ([]*Variable, error) {
|
func (scope *EvalScope) Locals(flags localsFlags) ([]*Variable, error) {
|
||||||
if scope.Fn == nil {
|
if scope.Fn == nil {
|
||||||
return nil, errors.New("unable to find function context")
|
return nil, errors.New("unable to find function context")
|
||||||
}
|
}
|
||||||
|
|
||||||
trustArgOrder := scope.trustArgOrder && scope.BinInfo.Producer() != "" && goversion.ProducerAfterOrEqual(scope.BinInfo.Producer(), 1, 12) && scope.Fn != nil && (scope.PC == scope.Fn.Entry)
|
trustArgOrder := (flags&localsTrustArgOrder != 0) && scope.BinInfo.Producer() != "" && goversion.ProducerAfterOrEqual(scope.BinInfo.Producer(), 1, 12) && scope.Fn != nil && (scope.PC == scope.Fn.Entry)
|
||||||
|
|
||||||
dwarfTree, err := scope.image().getDwarfTree(scope.Fn.offset)
|
dwarfTree, err := scope.image().getDwarfTree(scope.Fn.offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -214,6 +222,9 @@ func (scope *EvalScope) Locals() ([]*Variable, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
variablesFlags := reader.VariablesOnlyVisible
|
variablesFlags := reader.VariablesOnlyVisible
|
||||||
|
if flags&localsNoDeclLineCheck != 0 {
|
||||||
|
variablesFlags = reader.VariablesNoDeclLineCheck
|
||||||
|
}
|
||||||
if scope.BinInfo.Producer() != "" && goversion.ProducerAfterOrEqual(scope.BinInfo.Producer(), 1, 15) {
|
if scope.BinInfo.Producer() != "" && goversion.ProducerAfterOrEqual(scope.BinInfo.Producer(), 1, 15) {
|
||||||
variablesFlags |= reader.VariablesTrustDeclLine
|
variablesFlags |= reader.VariablesTrustDeclLine
|
||||||
}
|
}
|
||||||
@ -417,7 +428,7 @@ func (scope *EvalScope) SetVariable(name, value string) error {
|
|||||||
|
|
||||||
// LocalVariables returns all local variables from the current function scope.
|
// LocalVariables returns all local variables from the current function scope.
|
||||||
func (scope *EvalScope) LocalVariables(cfg LoadConfig) ([]*Variable, error) {
|
func (scope *EvalScope) LocalVariables(cfg LoadConfig) ([]*Variable, error) {
|
||||||
vars, err := scope.Locals()
|
vars, err := scope.Locals(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -431,7 +442,7 @@ func (scope *EvalScope) LocalVariables(cfg LoadConfig) ([]*Variable, error) {
|
|||||||
|
|
||||||
// FunctionArguments returns the name, value, and type of all current function arguments.
|
// FunctionArguments returns the name, value, and type of all current function arguments.
|
||||||
func (scope *EvalScope) FunctionArguments(cfg LoadConfig) ([]*Variable, error) {
|
func (scope *EvalScope) FunctionArguments(cfg LoadConfig) ([]*Variable, error) {
|
||||||
vars, err := scope.Locals()
|
vars, err := scope.Locals(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1134,7 +1145,7 @@ func (scope *EvalScope) evalIdent(node *ast.Ident) (*Variable, error) {
|
|||||||
return nilVariable, nil
|
return nilVariable, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
vars, err := scope.Locals()
|
vars, err := scope.Locals(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -883,9 +883,13 @@ func funcCallStep(callScope *EvalScope, fncall *functionCallState, thread Thread
|
|||||||
|
|
||||||
// pretend we are still inside the function we called
|
// pretend we are still inside the function we called
|
||||||
fakeFunctionEntryScope(retScope, fncall.fn, int64(regs.SP()), regs.SP()-uint64(bi.Arch.PtrSize()))
|
fakeFunctionEntryScope(retScope, fncall.fn, int64(regs.SP()), regs.SP()-uint64(bi.Arch.PtrSize()))
|
||||||
retScope.trustArgOrder = !bi.regabi
|
var flags localsFlags
|
||||||
|
flags |= localsNoDeclLineCheck // if the function we are calling is an autogenerated stub then declaration lines have no meaning
|
||||||
|
if !bi.regabi {
|
||||||
|
flags |= localsTrustArgOrder
|
||||||
|
}
|
||||||
|
|
||||||
fncall.retvars, err = retScope.Locals()
|
fncall.retvars, err = retScope.Locals(flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fncall.err = fmt.Errorf("could not get return values: %v", err)
|
fncall.err = fmt.Errorf("could not get return values: %v", err)
|
||||||
break
|
break
|
||||||
|
|||||||
@ -3544,7 +3544,7 @@ func testDeclLineCount(t *testing.T, p *proc.Target, lineno int, tgtvars []strin
|
|||||||
assertLineNumber(p, t, lineno, "Program did not continue to correct next location")
|
assertLineNumber(p, t, lineno, "Program did not continue to correct next location")
|
||||||
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
||||||
assertNoError(err, t, fmt.Sprintf("GoroutineScope (:%d)", lineno))
|
assertNoError(err, t, fmt.Sprintf("GoroutineScope (:%d)", lineno))
|
||||||
vars, err := scope.Locals()
|
vars, err := scope.Locals(0)
|
||||||
assertNoError(err, t, fmt.Sprintf("Locals (:%d)", lineno))
|
assertNoError(err, t, fmt.Sprintf("Locals (:%d)", lineno))
|
||||||
if len(vars) != len(tgtvars) {
|
if len(vars) != len(tgtvars) {
|
||||||
t.Fatalf("wrong number of variables %d (:%d)", len(vars), lineno)
|
t.Fatalf("wrong number of variables %d (:%d)", len(vars), lineno)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user