in tool/instrument/inst_func.go [341:428]
func (rp *RuleProcessor) applyFuncRules(bundle *resource.RuleBundle) (err error) {
// Nothing to do if no func rules
if len(bundle.File2FuncRules) == 0 {
return nil
}
// Copy API file to compilation working directory
err = rp.copyOtelApi(bundle.PackageName)
if err != nil {
return err
}
// Applied all matched func rules, either inserting raw code or inserting
// our trampoline calls.
for file, fn2rules := range bundle.File2FuncRules {
util.Assert(filepath.IsAbs(file), "file path must be absolute")
astRoot, err := rp.loadAst(file)
if err != nil {
return err
}
rp.trampolineJumps = make([]*TJump, 0)
// Since we may genarate many functions into the same file, while we dont
// want to further instrument these functions, we need to make sure that
// the generated function are exclued from the instrumented file.
oldDecls := make([]dst.Decl, len(astRoot.Decls))
copy(oldDecls, astRoot.Decls)
for fnName, rules := range fn2rules {
for _, decl := range oldDecls {
nameAndRecvType := strings.Split(fnName, ",")
name := nameAndRecvType[0]
recvType := nameAndRecvType[1]
if util.MatchFuncDecl(decl, name, recvType) {
fnDecl := decl.(*dst.FuncDecl)
util.Assert(fnDecl.Body != nil, "target func boby is empty")
fnName := fnDecl.Name.Name
// Save raw function declaration
rp.rawFunc = fnDecl
// The func rule can either fully match the target function
// or use a regexp to match a batch of functions. The
// generation of tjump differs slightly between these two
// cases. In the former case, the hook function is required
// to have the same signature as the target function, while
// the latter does not have this requirement.
rp.exact = fnName == name
// Add explicit names for return values, they can be further
// referenced if we're willing
nameReturnValues(fnDecl)
// Apply all matched rules for this function
fnRules := sortFuncRules(rules)
for _, rule := range fnRules {
if rule.UseRaw {
err = rp.insertRaw(rule, fnDecl)
} else {
err = rp.insertTJump(rule, fnDecl)
}
if err != nil {
return err
}
util.Log("Apply func rule %s (%v)", rule, rp.compileArgs)
}
// break
}
}
}
// Optimize generated trampoline-jump-ifs
err = rp.optimizeTJumps()
if err != nil {
return err
}
// Restore the ast to original file once all rules are applied
newFile, err := rp.restoreAst(file, astRoot)
if err != nil {
return err
}
// Line directive must be placed at the beginning of the line, otherwise
// it will be ignored by the compiler
err = rp.enableLineDirective(newFile)
if err != nil {
return err
}
rp.saveDebugFile(newFile)
}
err = rp.writeTrampoline(bundle.PackageName)
if err != nil {
return err
}
return nil
}