Skip to content

Commit 769dcdc

Browse files
committed
refactor(callstack): Use creator process id for callstack treatment
1 parent 8b42b66 commit 769dcdc

File tree

5 files changed

+60
-30
lines changed

5 files changed

+60
-30
lines changed

pkg/event/event_windows.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,24 @@ func (e *Event) IsOpenDisposition() bool {
267267
return e.IsCreateFile() && e.Params.MustGetUint32(params.FileOperation) == windows.FILE_OPEN
268268
}
269269

270-
// StackID returns the integer that is used to identify the callstack present in the StackWalk event.
271-
func (e *Event) StackID() uint64 { return uint64(e.PID + e.Tid) }
270+
// StackID returns the integer that is used to stich the callstack present in the StackWalk event.
271+
func (e *Event) StackID() uint64 {
272+
if e.IsCreateProcess() {
273+
return uint64(e.Params.MustGetPpid() + e.Tid)
274+
}
275+
return uint64(e.PID + e.Tid)
276+
}
277+
278+
// StackPID returns the process id as seen the creator
279+
// from the callstack execution perspective. For example,
280+
// the pid associated with CreateProcess events is the
281+
// parent, not the process being created.
282+
func (e *Event) StackPID() uint32 {
283+
if e.IsCreateProcess() {
284+
return e.Params.MustGetPpid()
285+
}
286+
return e.PID
287+
}
272288

273289
// RundownKey calculates the rundown event hash. The hash is
274290
// used to determine if the rundown event was already processed.

pkg/filter/accessor_windows.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -563,13 +563,13 @@ func (t *threadAccessor) Get(f Field, e *event.Event) (params.Value, error) {
563563

564564
return e.Callstack.Symbols(), nil
565565
case fields.ThreadCallstackAllocationSizes:
566-
return e.Callstack.AllocationSizes(e.PID), nil
566+
return e.Callstack.AllocationSizes(framePID(e)), nil
567567
case fields.ThreadCallstackProtections:
568-
return e.Callstack.Protections(e.PID), nil
568+
return e.Callstack.Protections(framePID(e)), nil
569569
case fields.ThreadCallstackCallsiteLeadingAssembly:
570-
return e.Callstack.CallsiteInsns(e.PID, true), nil
570+
return e.Callstack.CallsiteInsns(framePID(e), true), nil
571571
case fields.ThreadCallstackCallsiteTrailingAssembly:
572-
return e.Callstack.CallsiteInsns(e.PID, false), nil
572+
return e.Callstack.CallsiteInsns(framePID(e), false), nil
573573
case fields.ThreadCallstackIsUnbacked:
574574
return e.Callstack.ContainsUnbacked(), nil
575575
case fields.ThreadCallstack:

pkg/filter/util.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919
package filter
2020

2121
import (
22+
"path/filepath"
23+
2224
"github.com/rabbitstack/fibratus/pkg/event"
2325
"github.com/rabbitstack/fibratus/pkg/event/params"
2426
"github.com/rabbitstack/fibratus/pkg/filter/fields"
2527
"github.com/rabbitstack/fibratus/pkg/util/loldrivers"
2628
"github.com/rabbitstack/fibratus/pkg/util/signature"
2729
"github.com/rabbitstack/fibratus/pkg/util/va"
28-
"path/filepath"
2930
)
3031

3132
// isLOLDriver interacts with the loldrivers client to determine
@@ -104,3 +105,11 @@ func getSignature(addr va.Address, filename string, parseCert bool) *signature.S
104105

105106
return sign
106107
}
108+
109+
// framePID returns the pid associated with the stack frame.
110+
func framePID(e *event.Event) uint32 {
111+
if !e.Callstack.IsEmpty() && e.Callstack.FrameAt(0).PID != 0 {
112+
return e.Callstack.FrameAt(0).PID
113+
}
114+
return e.PID
115+
}

pkg/symbolize/symbolizer.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -398,9 +398,10 @@ func (s *Symbolizer) processCallstack(e *event.Event) error {
398398
return nil
399399
}
400400

401-
proc, ok := s.procs[e.PID]
401+
pid := e.StackPID()
402+
proc, ok := s.procs[pid]
402403
if !ok {
403-
handle, err := windows.OpenProcess(windows.SYNCHRONIZE|windows.PROCESS_QUERY_INFORMATION, false, e.PID)
404+
handle, err := windows.OpenProcess(windows.SYNCHRONIZE|windows.PROCESS_QUERY_INFORMATION, false, pid)
404405
if err != nil {
405406
s.pushFrames(addrs, e)
406407
return err
@@ -410,10 +411,10 @@ func (s *Symbolizer) processCallstack(e *event.Event) error {
410411
err = s.r.Initialize(handle, opts)
411412
if err != nil {
412413
s.pushFrames(addrs, e)
413-
return ErrSymInitialize(e.PID)
414+
return ErrSymInitialize(pid)
414415
}
415-
proc = &process{e.PID, handle, time.Now(), 1}
416-
s.procs[e.PID] = proc
416+
proc = &process{pid, handle, time.Now(), 1}
417+
s.procs[pid] = proc
417418
}
418419

419420
s.pushFrames(addrs, e)
@@ -442,7 +443,8 @@ func (s *Symbolizer) pushFrames(addrs []va.Address, e *event.Event) {
442443
// symbol or module are not resolved, then we
443444
// fall back to Debug API.
444445
func (s *Symbolizer) produceFrame(addr va.Address, e *event.Event) callstack.Frame {
445-
frame := callstack.Frame{PID: e.PID, Addr: addr}
446+
pid := e.StackPID()
447+
frame := callstack.Frame{PID: pid, Addr: addr}
446448
if addr.InSystemRange() {
447449
if s.config.SymbolizeKernelAddresses {
448450
frame.Module = s.r.GetModuleName(windows.CurrentProcess(), addr)
@@ -452,7 +454,7 @@ func (s *Symbolizer) produceFrame(addr va.Address, e *event.Event) callstack.Fra
452454
}
453455

454456
// did we hit this address previously?
455-
if sym, ok := s.symbols[e.PID]; ok {
457+
if sym, ok := s.symbols[pid]; ok {
456458
if symbol, ok := sym[addr]; ok {
457459
symCacheHits.Add(1)
458460
frame.Module, frame.Symbol, frame.ModuleAddress = symbol.module, symbol.symbol, symbol.moduleAddress
@@ -468,7 +470,7 @@ func (s *Symbolizer) produceFrame(addr va.Address, e *event.Event) callstack.Fra
468470
}
469471
if mod == nil {
470472
// our last resort is to enumerate process modules
471-
modules := sys.EnumProcessModules(e.PID)
473+
modules := sys.EnumProcessModules(pid)
472474
for _, m := range modules {
473475
b := va.Address(m.BaseOfDll)
474476
size := uint64(m.SizeOfImage)
@@ -526,17 +528,17 @@ func (s *Symbolizer) produceFrame(addr va.Address, e *event.Event) callstack.Fra
526528
}
527529
if frame.Module != "" && frame.Symbol != "" {
528530
// store resolved symbol information in cache
529-
s.cacheSymbol(e.PID, addr, &frame)
531+
s.cacheSymbol(pid, addr, &frame)
530532
return frame
531533
}
532534
}
533535

534536
debugHelpFallbacks.Add(1)
535537

536538
// fallback to Debug Help API
537-
proc, ok := s.procs[e.PID]
539+
proc, ok := s.procs[pid]
538540
if !ok {
539-
handle, err := windows.OpenProcess(windows.SYNCHRONIZE|windows.PROCESS_QUERY_INFORMATION, false, e.PID)
541+
handle, err := windows.OpenProcess(windows.SYNCHRONIZE|windows.PROCESS_QUERY_INFORMATION, false, pid)
540542
if err != nil {
541543
return frame
542544
}
@@ -546,8 +548,8 @@ func (s *Symbolizer) produceFrame(addr va.Address, e *event.Event) callstack.Fra
546548
if err != nil {
547549
return frame
548550
}
549-
proc = &process{e.PID, handle, time.Now(), 1}
550-
s.procs[e.PID] = proc
551+
proc = &process{pid, handle, time.Now(), 1}
552+
s.procs[pid] = proc
551553
}
552554

553555
proc.keepalive()
@@ -564,7 +566,7 @@ func (s *Symbolizer) produceFrame(addr va.Address, e *event.Event) callstack.Fra
564566
}
565567

566568
// store resolved symbol information in cache
567-
s.cacheSymbol(e.PID, addr, &frame)
569+
s.cacheSymbol(pid, addr, &frame)
568570

569571
return frame
570572
}

pkg/symbolize/symbolizer_test.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
package symbolize
2020

2121
import (
22+
"math/rand"
23+
"os"
24+
"path/filepath"
25+
"testing"
26+
"time"
27+
2228
"github.com/rabbitstack/fibratus/pkg/config"
2329
"github.com/rabbitstack/fibratus/pkg/event"
2430
"github.com/rabbitstack/fibratus/pkg/event/params"
@@ -33,11 +39,6 @@ import (
3339
"github.com/stretchr/testify/mock"
3440
"github.com/stretchr/testify/require"
3541
"golang.org/x/sys/windows"
36-
"math/rand"
37-
"os"
38-
"path/filepath"
39-
"testing"
40-
"time"
4142
)
4243

4344
// MockResolver for unit testing
@@ -282,15 +283,16 @@ func TestProcessCallstack(t *testing.T) {
282283
e := &event.Event{
283284
Type: event.CreateProcess,
284285
Tid: 2484,
285-
PID: uint32(os.Getpid()),
286+
PID: 2232,
286287
CPU: 1,
287288
Seq: 2,
288289
Name: "CreatedProcess",
289290
Timestamp: time.Now(),
290291
Category: event.Process,
291292
Host: "archrabbit",
292293
Params: event.Params{
293-
params.Callstack: {Name: params.Callstack, Type: params.Slice, Value: []va.Address{0x7ffb5c1d0396, 0x7ffb5d8e61f4, 0x7ffb3138592e, 0x7ffb313853b2, 0x2638e59e0a5}},
294+
params.ProcessParentID: {Name: params.ProcessParentID, Type: params.PID, Value: (uint32(os.Getpid()))},
295+
params.Callstack: {Name: params.Callstack, Type: params.Slice, Value: []va.Address{0x7ffb5c1d0396, 0x7ffb5d8e61f4, 0x7ffb3138592e, 0x7ffb313853b2, 0x2638e59e0a5}},
294296
},
295297
PS: proc,
296298
}
@@ -454,15 +456,16 @@ func TestProcessCallstackProcsTTL(t *testing.T) {
454456
e := &event.Event{
455457
Type: event.CreateProcess,
456458
Tid: 2484,
457-
PID: uint32(os.Getpid()),
459+
PID: 1232,
458460
CPU: 1,
459461
Seq: 2,
460462
Name: "CreatedProcess",
461463
Timestamp: time.Now().Add(time.Millisecond * time.Duration(n)),
462464
Category: event.Process,
463465
Host: "archrabbit",
464466
Params: event.Params{
465-
params.Callstack: {Name: params.Callstack, Type: params.Slice, Value: []va.Address{0x7ffb5c1d0396, 0x7ffb5d8e61f4, 0x7ffb3138592e, 0x7ffb313853b2, 0x2638e59e0a5}},
467+
params.ProcessParentID: {Name: params.ProcessParentID, Type: params.PID, Value: (uint32(os.Getpid()))},
468+
params.Callstack: {Name: params.Callstack, Type: params.Slice, Value: []va.Address{0x7ffb5c1d0396, 0x7ffb5d8e61f4, 0x7ffb3138592e, 0x7ffb313853b2, 0x2638e59e0a5}},
466469
},
467470
}
468471
_, _ = s.ProcessEvent(e)

0 commit comments

Comments
 (0)