Save addresses for "allowed" functions.

PiperOrigin-RevId: 335086850
This commit is contained in:
Adin Scannell 2020-10-02 13:12:22 -07:00 committed by gVisor bot
parent 4f462b0ed9
commit 0cea647218
1 changed files with 81 additions and 46 deletions

View File

@ -398,7 +398,37 @@ func loadObjdump() (map[string][]string, error) {
return nil, err
}
// Identify calls by address or name. Note that this is also
// constructed dynamically below, as we encounted the addresses.
// This is because some of the functions (duffzero) may have
// jump targets in the middle of the function itself.
funcsAllowed := map[string]struct{}{
"runtime.duffzero": struct{}{},
"runtime.duffcopy": struct{}{},
"runtime.racefuncenter": struct{}{},
"runtime.gcWriteBarrier": struct{}{},
"runtime.retpolineAX": struct{}{},
"runtime.retpolineBP": struct{}{},
"runtime.retpolineBX": struct{}{},
"runtime.retpolineCX": struct{}{},
"runtime.retpolineDI": struct{}{},
"runtime.retpolineDX": struct{}{},
"runtime.retpolineR10": struct{}{},
"runtime.retpolineR11": struct{}{},
"runtime.retpolineR12": struct{}{},
"runtime.retpolineR13": struct{}{},
"runtime.retpolineR14": struct{}{},
"runtime.retpolineR15": struct{}{},
"runtime.retpolineR8": struct{}{},
"runtime.retpolineR9": struct{}{},
"runtime.retpolineSI": struct{}{},
"runtime.stackcheck": struct{}{},
"runtime.settls": struct{}{},
}
addrsAllowed := make(map[string]struct{})
// Build the map.
nextFunc := "" // For funcsAllowed.
m := make(map[string][]string)
r := bufio.NewReader(out)
NextLine:
@ -407,6 +437,20 @@ NextLine:
if err != nil && err != io.EOF {
return nil, err
}
fields := strings.Fields(line)
// Is this an "allowed" function definition?
if len(fields) >= 2 && fields[0] == "TEXT" {
if _, ok := funcsAllowed[fields[1]]; ok {
nextFunc = strings.TrimSuffix(fields[1], "(SB)")
} else {
nextFunc = "" // Don't record addresses.
}
}
if nextFunc != "" && len(fields) > 2 {
// Save the given address (in hex form, as it appears).
addrsAllowed[fields[1]] = struct{}{}
}
// We recognize lines corresponding to actual code (not the
// symbol name or other metadata) and annotate them if they
@ -416,53 +460,31 @@ NextLine:
//
// Lines look like this (including the first space):
// gohacks_unsafe.go:33 0xa39 488b442408 MOVQ 0x8(SP), AX
if len(line) > 0 && line[0] == ' ' {
fields := strings.Fields(line)
if len(fields) >= 5 && line[0] == ' ' {
if !strings.Contains(fields[3], "CALL") {
continue
}
site := strings.TrimSpace(fields[0])
var callStr string // Friendly string.
site := fields[0]
target := strings.TrimSuffix(fields[4], "(SB)")
// Ignore strings containing allowed functions.
if _, ok := funcsAllowed[target]; ok {
continue
}
if _, ok := addrsAllowed[target]; ok {
continue
}
if len(fields) > 5 {
callStr = strings.Join(fields[5:], " ")
}
if len(callStr) == 0 {
// Just a raw call? is this asm?
callStr = strings.Join(fields[3:], " ")
}
// Ignore strings containing duffzero, which is just
// used by stack allocations for types that are large
// enough to warrant Duff's device.
if strings.Contains(callStr, "runtime.duffzero") ||
strings.Contains(callStr, "runtime.duffcopy") {
continue
}
// Ignore the racefuncenter call, which is used for
// race builds. This does not escape.
if strings.Contains(callStr, "runtime.racefuncenter") {
continue
}
// Ignore the write barriers.
if strings.Contains(callStr, "runtime.gcWriteBarrier") {
continue
}
// Ignore retpolines.
if strings.Contains(callStr, "runtime.retpoline") {
continue
}
// Ignore stack sanity check (does not split).
if strings.Contains(callStr, "runtime.stackcheck") {
continue
}
// Ignore tls functions.
if strings.Contains(callStr, "runtime.settls") {
continue
// This may be a future relocation. Some
// objdump versions describe this differently.
// If it contains any of the functions allowed
// above as a string, we let it go.
softTarget := strings.Join(fields[5:], " ")
for name := range funcsAllowed {
if strings.Contains(softTarget, name) {
continue NextLine
}
}
}
// Does this exist already?
@ -471,11 +493,11 @@ NextLine:
existing = make([]string, 0, 1)
}
for _, other := range existing {
if callStr == other {
if target == other {
continue NextLine
}
}
existing = append(existing, callStr)
existing = append(existing, target)
m[site] = existing // Update.
}
if err == io.EOF {
@ -483,12 +505,25 @@ NextLine:
}
}
// Zap any accidental false positives.
final := make(map[string][]string)
for site, calls := range m {
filteredCalls := make([]string, 0, len(calls))
for _, call := range calls {
if _, ok := addrsAllowed[call]; ok {
continue // Omit this call.
}
filteredCalls = append(filteredCalls, call)
}
final[site] = filteredCalls
}
// Wait for the dump to finish.
if err := cmd.Wait(); err != nil {
return nil, err
}
return m, nil
return final, nil
}
// poser is a type that implements Pos.