Skip to content
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

Attach all insns matching the same line, output with CALL #9

Merged
merged 1 commit into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bpf/bpf_x86_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified bpf/bpf_x86_bpfel.o
Binary file not shown.
56 changes: 56 additions & 0 deletions bpf/ktcpdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct event {
u64 skb;
u32 skb_len;
u32 data_len;
u64 call;
u16 protocol;
u8 has_mac;
};
Expand Down Expand Up @@ -131,6 +132,60 @@ kprobe_pcap_filter(struct sk_buff *skb, u8 *has_mac)
data, data_end);
}

static __always_inline void
get_call_target(struct pt_regs *ctx, u64 *call, u64 cookie)
{
switch (cookie) {
case 1:
BPF_CORE_READ_INTO(call, ctx, r15);
break;
case 2:
BPF_CORE_READ_INTO(call, ctx, r14);
break;
case 3:
BPF_CORE_READ_INTO(call, ctx, r13);
break;
case 4:
BPF_CORE_READ_INTO(call, ctx, r12);
break;
case 5:
BPF_CORE_READ_INTO(call, ctx, bp);
break;
case 6:
BPF_CORE_READ_INTO(call, ctx, bx);
break;
case 7:
BPF_CORE_READ_INTO(call, ctx, r11);
break;
case 8:
BPF_CORE_READ_INTO(call, ctx, r10);
break;
case 9:
BPF_CORE_READ_INTO(call, ctx, r9);
break;
case 10:
BPF_CORE_READ_INTO(call, ctx, r8);
break;
case 11:
BPF_CORE_READ_INTO(call, ctx, ax);
break;
case 12:
BPF_CORE_READ_INTO(call, ctx, cx);
break;
case 13:
BPF_CORE_READ_INTO(call, ctx, dx);
break;
case 14:
BPF_CORE_READ_INTO(call, ctx, si);
break;
case 15:
BPF_CORE_READ_INTO(call, ctx, di);
break;
default:
*call = 0;
}
}

SEC("kprobe/skb_by_search")
int kprobe_skb_by_search(struct pt_regs *ctx)
{
Expand All @@ -154,6 +209,7 @@ int kprobe_skb_by_search(struct pt_regs *ctx)
event->skb = (u64)skb;
event->skb_len = BPF_CORE_READ(skb, len);
event->protocol = BPF_CORE_READ(skb, protocol);
get_call_target(ctx, &event->call, bpf_get_attach_cookie(ctx));

u16 off_l2_or_l3 = event->has_mac
? BPF_CORE_READ(skb, mac_header)
Expand Down
43 changes: 38 additions & 5 deletions kcore.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ type Kcore struct {
elf *elf.File
}

type Instruction struct {
Symbol string
Offset uint64
Call bool
CallTarget string
*LineInfo
}

func NewKcore() (*Kcore, error) {
file, err := os.Open(kcorePath)
if err != nil {
Expand All @@ -47,9 +55,8 @@ func GetKcore() (_ *Kcore, err error) {
return kcore, err
}

func (k *Kcore) FindLines(symbol string) (lineInfos map[LineInfo][]uint64, err error) {
lineInfos = make(map[LineInfo][]uint64)

func (k *Kcore) ParseInsns(symbol string) (insns map[uint64]*Instruction, err error) {
insns = make(map[uint64]*Instruction)
kdwarf, err := GetKdwarf()
if err != nil {
return
Expand Down Expand Up @@ -79,10 +86,37 @@ func (k *Kcore) FindLines(symbol string) (lineInfos map[LineInfo][]uint64, err e
inst = x86asm.Inst{Len: 1}
off += 1
} else {
insn := Instruction{
Symbol: symbol,
Offset: uint64(off),
}
if inst.Op == x86asm.CALL {
insn.Call = true
for _, arg := range inst.Args {
if arg == nil {
break
}
rel, ok := arg.(x86asm.Rel)
if !ok {
reg, ok := arg.(x86asm.Reg)
if ok {
insn.CallTarget = reg.String()
break
}
}
callee := addr + uint64(off) + uint64(rel) + uint64(inst.Len)
ksym, err := KsymByAddr(callee)
if err == nil {
insn.CallTarget = ksym.Name
}
break
}
}
lineInfo, err := kdwarf.GetLineInfo(symbol, uint64(off))
if err == nil {
lineInfos[*lineInfo] = append(lineInfos[*lineInfo], uint64(off))
insn.LineInfo = lineInfo
}
insns[uint64(off)] = &insn
}

bytes = bytes[inst.Len:]
Expand All @@ -91,7 +125,6 @@ func (k *Kcore) FindLines(symbol string) (lineInfos map[LineInfo][]uint64, err e
break
}
}

}
}

Expand Down
70 changes: 37 additions & 33 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ func main() {
defer k.Close()

var attachByLine bool
allInsns := map[string]map[uint64]*Instruction{}
for _, target := range config.Targets {
match := targetPattern.FindStringSubmatch(target)
result := make(map[string]string)
Expand Down Expand Up @@ -164,23 +165,24 @@ func main() {
log.Error("Failed to new kcore", "err", err)
return
}
jumps, err := kcore.FindLines(symbol)
insns, err := kcore.ParseInsns(symbol)
if err != nil {
log.Error("Failed to find jumps", "symbol", symbol, "err", err)
log.Error("Failed to find lines", "symbol", symbol, "err", err)
return
}
for _, js := range jumps {
for _, j := range js {
log.Debug("Attaching", "symbol", symbol, "offset", j)
k, err := link.Kprobe(symbol, objs.KprobeSkbBySearch, &link.KprobeOptions{Offset: j})
if err != nil {
log.Debug("Failed to attach targets", "symbol", symbol, "offset", j, "err", err)
continue
}
defer k.Close()
break
allInsns[symbol] = insns

for _, ins := range insns {
cookie := RegisterToCookie(ins.CallTarget)
log.Debug("Attaching", "symbol", ins.Symbol, "offset", ins.Offset, "cookie", cookie)
k, err := link.Kprobe(symbol, objs.KprobeSkbBySearch, &link.KprobeOptions{Offset: ins.Offset, Cookie: cookie})
if err != nil {
log.Debug("Failed to attach targets", "symbol", symbol, "offset", ins.Offset, "err", err)
continue
}
defer k.Close()
}

} else {
k, err = link.Kprobe(symbol, objs.KprobeSkbBySearch, &link.KprobeOptions{Offset: offset})
if err != nil {
Expand All @@ -191,15 +193,6 @@ func main() {
}
}

var kdwarf *Kdwarf
if attachByLine {
kdwarf, err = GetKdwarf()
if err != nil {
log.Error("Failed to get kdwarf", "err", err)
return
}
}

skbBuildFuncs := []string{}
btfSpec, err := btf.LoadKernelSpec()
if err != nil {
Expand Down Expand Up @@ -275,11 +268,7 @@ func main() {
return
}

fmt.Printf("%-4s %-18s %-10s %-18s %-16s", "no", "skb", "skb->len", "pc", "ksym")
if attachByLine {
fmt.Printf(" addr2line")
}
fmt.Println()
fmt.Printf("%-4s %-18s %-10s %-18s %-16s\n", "no", "skb", "skb->len", "pc", "ksym")
i := 0

for {
Expand All @@ -303,19 +292,34 @@ func main() {
log.Error("Failed to get dwarf", "err", err)
return
}
sym, _ := NearestKsym(event.At)
ksym, _ := NearestKsym(event.At)

var lineInfo *LineInfo
var insn *Instruction
if attachByLine {
lineInfo, err = kdwarf.GetLineInfo(sym.Name, event.At-sym.Addr-1)
if err != nil {
lineInfo, err = kdwarf.GetLineInfo(sym.Name, event.At-sym.Addr-4)
var ok bool
insn, ok = allInsns[ksym.Name][event.At-ksym.Addr-1]
if !ok {
insn, ok = allInsns[ksym.Name][event.At-ksym.Addr-4]
if !ok {
log.Error("Failed to find insn", "symbol", ksym.Name, "offset", event.At-ksym.Addr)
return
}
}
}

fmt.Printf("%-4d %-18x %-10d %-18x %-16s", i, event.Skb, event.SkbLen, event.At, fmt.Sprintf("%s+%d", sym.Name, event.At-sym.Addr))
fmt.Printf("%-4d %-18x %-10d %-18x %-16s", i, event.Skb, event.SkbLen, event.At, fmt.Sprintf("%s+%d", ksym.Name, event.At-ksym.Addr))
if attachByLine {
fmt.Printf(" %s:%d", lineInfo.Filename, lineInfo.Line)
if insn.LineInfo != nil {
fmt.Printf(" %s:%d", insn.Filename, insn.Line)
}
if insn.Call {
ksym, err := KsymByAddr(event.Call)
if event.Call != 0 && err == nil {
fmt.Printf(" // CALL %s", ksym.Name)
} else {
fmt.Printf(" // CALL %s", insn.CallTarget)
}
}
}
fmt.Println()

Expand Down
40 changes: 38 additions & 2 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,51 @@ func IsDigit(c string) (uint64, bool) {
}
}

address, err := strconv.ParseUint(c, 16, 64)
address, err := strconv.ParseUint(c, 10, 64)
if err == nil {
return address, true
}

address, err = strconv.ParseUint(c, 10, 64)
address, err = strconv.ParseUint(c, 16, 64)
if err == nil {
return address, true
}

return 0, false
}

func RegisterToCookie(register string) (cookie uint64) {
switch register {
case "R15":
cookie = 1
case "R14":
cookie = 2
case "R13":
cookie = 3
case "R12":
cookie = 4
case "RBP":
cookie = 5
case "RBX":
cookie = 6
case "R11":
cookie = 7
case "R10":
cookie = 8
case "R9":
cookie = 9
case "R8":
cookie = 10
case "RAX":
cookie = 11
case "RCX":
cookie = 12
case "RDX":
cookie = 13
case "RSI":
cookie = 14
case "RDI":
cookie = 15
}
return
}
Loading