@@ -298,9 +298,25 @@ func (s *Symbolizer) processCallstack(e *kevent.Kevent) error {
298298 defer s .mu .Unlock ()
299299
300300 if e .PS != nil {
301+ // symbolize thread start address
302+ if e .IsCreateThread () && ! e .IsSystemPid () {
303+ addr := e .Kparams .TryGetAddress (kparams .StartAddress )
304+
305+ mod := e .PS .FindModuleByVa (addr )
306+ symbol := s .symbolizeAddress (e .Kparams .MustGetPid (), addr , mod )
307+
308+ if symbol != "" {
309+ e .Kparams .Append (kparams .StartAddressSymbol , kparams .UnicodeString , symbol )
310+ }
311+ if mod != nil {
312+ e .Kparams .Append (kparams .StartAddressModule , kparams .UnicodeString , mod .Name )
313+ }
314+ }
315+
301316 // try to resolve addresses from process
302317 // state and PE export directory data
303318 s .pushFrames (addrs , e , false , true )
319+
304320 return nil
305321 }
306322
@@ -504,6 +520,60 @@ func (s *Symbolizer) resolveSymbolFromExportDirectory(addr va.Address, mod *psty
504520 return symbolFromRVA (rva , px .Exports )
505521}
506522
523+ // symbolizeAddress resolves the given address to a symbol. If the symbol
524+ // for this address was resolved previously, we fetch it from the cache.
525+ // On the contrary, the symbol is first consulted in the export directory.
526+ // If not found, the Debug Help API is used to symbolize the address.
527+ func (s * Symbolizer ) symbolizeAddress (pid uint32 , addr va.Address , mod * pstypes.Module ) string {
528+ if addr .InSystemRange () {
529+ return ""
530+ }
531+
532+ symbol , ok := s.symbols [pid ][addr ]
533+ if ! ok && mod != nil {
534+ // resolve symbol from the export directory
535+ symbol = s .resolveSymbolFromExportDirectory (addr , mod )
536+ }
537+
538+ // try to get the symbol via Debug Help API
539+ if symbol == "" {
540+ proc , ok := s .procs [pid ]
541+ if ! ok {
542+ handle , err := windows .OpenProcess (windows .SYNCHRONIZE | windows .PROCESS_QUERY_INFORMATION , false , pid )
543+ if err != nil {
544+ return ""
545+ }
546+
547+ // initialize symbol handler
548+ opts := uint32 (sys .SymUndname | sys .SymCaseInsensitive | sys .SymAutoPublics | sys .SymOmapFindNearest | sys .SymDeferredLoads )
549+ err = s .r .Initialize (handle , opts )
550+ if err != nil {
551+ return ""
552+ }
553+
554+ proc = & process {pid , handle , time .Now (), 1 }
555+ s .procs [pid ] = proc
556+
557+ // resolve address to symbol
558+ symbol , _ = s .r .GetSymbolNameAndOffset (handle , addr )
559+ } else {
560+ symbol , _ = s .r .GetSymbolNameAndOffset (proc .handle , addr )
561+ proc .keepalive ()
562+ }
563+ }
564+
565+ // cache the resolved symbol
566+ if addrs , ok := s .symbols [pid ]; ok {
567+ if _ , ok := addrs [addr ]; ! ok {
568+ s.symbols [pid ][addr ] = symbol
569+ }
570+ } else {
571+ s .symbols [pid ] = map [va.Address ]string {addr : symbol }
572+ }
573+
574+ return symbol
575+ }
576+
507577// symbolFromRVA finds the closest export address before RVA.
508578func symbolFromRVA (rva va.Address , exports map [uint32 ]string ) string {
509579 var exp uint32
0 commit comments