@@ -380,11 +380,17 @@ func (ctx *linux) extractContext(line []byte) string {
380380}
381381
382382func (ctx * linux ) Symbolize (rep * Report ) error {
383+ var symbFunc symbFuncCb
383384 if ctx .vmlinux != "" {
384- if err := ctx .symbolize (rep ); err != nil {
385- return err
385+ symb := symbolizer .Make (ctx .config .target )
386+ defer symb .Close ()
387+ symbFunc = func (bin string , pc uint64 ) ([]symbolizer.Frame , error ) {
388+ return ctx .symbolizerCache .Symbolize (symb .Symbolize , bin , pc )
386389 }
387390 }
391+ if err := ctx .symbolize (rep , symbFunc ); err != nil {
392+ return err
393+ }
388394 rep .Report = ctx .decompileOpcodes (rep .Report , rep )
389395
390396 // Skip getting maintainers for Android fuzzing since the kernel source
@@ -406,17 +412,25 @@ func (ctx *linux) Symbolize(rep *Report) error {
406412 return nil
407413}
408414
409- func (ctx * linux ) symbolize (rep * Report ) error {
410- symb := symbolizer .Make (ctx .config .target )
411- defer symb .Close ()
412- symbFunc := func (bin string , pc uint64 ) ([]symbolizer.Frame , error ) {
413- return ctx .symbolizerCache .Symbolize (symb .Symbolize , bin , pc )
414- }
415+ type symbFuncCb = func (string , uint64 ) ([]symbolizer.Frame , error )
416+
417+ func (ctx * linux ) symbolize (rep * Report , symbFunc symbFuncCb ) error {
415418 var symbolized []byte
416419 prefix := rep .reportPrefixLen
417420 for _ , line := range bytes .SplitAfter (rep .Report , []byte ("\n " )) {
418- line := bytes .Clone (line )
419- newLine := symbolizeLine (symbFunc , ctx , line )
421+ var newLine []byte
422+ parsed , ok := parseLinuxBacktraceLine (line )
423+ if ok {
424+ lines := []linuxBacktraceLine {parsed }
425+ if symbFunc != nil {
426+ lines = symbolizeLine (symbFunc , ctx , parsed )
427+ }
428+ for _ , line := range lines {
429+ newLine = append (newLine , line .Assemble ()... )
430+ }
431+ } else {
432+ newLine = line
433+ }
420434 if prefix > len (symbolized ) {
421435 prefix += len (newLine ) - len (line )
422436 }
@@ -436,72 +450,111 @@ func (ctx *linux) symbolize(rep *Report) error {
436450 return nil
437451}
438452
439- func symbolizeLine (symbFunc func (bin string , pc uint64 ) ([]symbolizer.Frame , error ), ctx * linux , line []byte ) []byte {
453+ type linuxBacktraceLine struct {
454+ // Fields and corresponding indices in the indices array.
455+ Name string // 2:3
456+ Offset uint64 // 4:5
457+ Size uint64 // 6:7
458+ // ... 8:9 is a ModName + its enclosing parentheses.
459+ ModName string // 10:11
460+ BuildID string // 12:13
461+ IsRipFrame bool
462+ // These fields are to be set externally.
463+ Inline bool
464+ FileLine string
465+ // These fields are not to be modified outside of the type's methods.
466+ raw []byte
467+ indices []int
468+ }
469+
470+ func parseLinuxBacktraceLine (line []byte ) (info linuxBacktraceLine , ok bool ) {
440471 match := linuxSymbolizeRe .FindSubmatchIndex (line )
441472 if match == nil {
442- return line
473+ return
443474 }
444- fn := line [match [2 ]:match [3 ]]
445- off , err := strconv .ParseUint (string (line [match [4 ]:match [5 ]]), 16 , 64 )
475+ info .raw = line
476+ info .indices = match
477+ info .Name = string (line [match [2 ]:match [3 ]])
478+ var err error
479+ info .Offset , err = strconv .ParseUint (string (line [match [4 ]:match [5 ]]), 16 , 64 )
446480 if err != nil {
447- return line
481+ return
448482 }
449- size , err : = strconv .ParseUint (string (line [match [6 ]:match [7 ]]), 16 , 64 )
483+ info . Size , err = strconv .ParseUint (string (line [match [6 ]:match [7 ]]), 16 , 64 )
450484 if err != nil {
451- return line
485+ return
452486 }
453- modName := ""
454487 if match [10 ] != - 1 && match [11 ] != - 1 {
455- modName = string (line [match [10 ]:match [11 ]])
488+ info . ModName = string (line [match [10 ]:match [11 ]])
456489 }
457- buildID := ""
458490 if match [12 ] != - 1 && match [13 ] != - 1 {
459- buildID = string (line [match [12 ]:match [13 ]])
491+ info .BuildID = string (line [match [12 ]:match [13 ]])
492+ }
493+ info .IsRipFrame = linuxRipFrame .Match (line )
494+ return info , true
495+ }
496+
497+ // Note that Assemble() ignores changes to Offset and Size (no reason as these are not updated anywhere).
498+ func (line linuxBacktraceLine ) Assemble () []byte {
499+ match := line .indices
500+ modified := append ([]byte {}, line .raw ... )
501+ if line .BuildID != "" {
502+ modified = replace (modified , match [8 ], match [9 ], []byte (" [" + line .ModName + "]" ))
503+ }
504+ if line .FileLine != "" {
505+ modified = replace (modified , match [7 ], match [7 ], []byte (line .FileLine ))
460506 }
461- symb := ctx .symbols [modName ][string (fn )]
507+ if line .Inline {
508+ end := match [7 ] + len (line .FileLine )
509+ modified = replace (modified , end , end , []byte (" [inline]" ))
510+ modified = replace (modified , match [2 ], match [7 ], []byte (line .Name ))
511+ } else {
512+ modified = replace (modified , match [2 ], match [3 ], []byte (line .Name ))
513+ }
514+ return modified
515+ }
516+
517+ func symbolizeLine (symbFunc func (bin string , pc uint64 ) ([]symbolizer.Frame , error ), ctx * linux ,
518+ parsed linuxBacktraceLine ) []linuxBacktraceLine {
519+ symb := ctx.symbols [parsed.ModName ][parsed.Name ]
462520 if len (symb ) == 0 {
463- return line
521+ return [] linuxBacktraceLine { parsed }
464522 }
465523 var funcStart uint64
466524 for _ , s := range symb {
467- if funcStart == 0 || int (size ) == s .Size {
525+ if funcStart == 0 || int (parsed . Size ) == s .Size {
468526 funcStart = s .Addr
469527 }
470528 }
471- pc := funcStart + off
472- if ! linuxRipFrame . Match ( line ) {
529+ pc := funcStart + parsed . Offset
530+ if ! parsed . IsRipFrame {
473531 // Usually we have return PCs, so we need to look at the previous instruction.
474532 // But RIP lines contain the exact faulting PC.
475533 pc --
476534 }
477535 var bin string
478536 for _ , mod := range ctx .config .kernelModules {
479- if mod .Name == modName {
537+ if mod .Name == parsed . ModName {
480538 bin = mod .Path
481539 break
482540 }
483541 }
484542 frames , err := symbFunc (bin , pc )
485543 if err != nil || len (frames ) == 0 {
486- return line
544+ return [] linuxBacktraceLine { parsed }
487545 }
488- var symbolized []byte
546+ var ret []linuxBacktraceLine
489547 for _ , frame := range frames {
490548 path , _ := backend .CleanPath (frame .File , & ctx .kernelDirs , nil )
491- info := fmt .Sprintf (" %v:%v" , path , frame .Line )
492- modified := append ([]byte {}, line ... )
493- if buildID != "" {
494- modified = replace (modified , match [8 ], match [9 ], []byte (" [" + modName + "]" ))
495- }
496- modified = replace (modified , match [7 ], match [7 ], []byte (info ))
549+ copy := parsed
550+ copy .FileLine = fmt .Sprintf (" %v:%v" , path , frame .Line )
497551 if frame .Inline {
498- end := match [7 ] + len (info )
499- modified = replace (modified , end , end , []byte (" [inline]" ))
500- modified = replace (modified , match [2 ], match [7 ], []byte (frame .Func ))
552+ copy .Inline = true
553+ copy .Name = frame .Func
501554 }
502- symbolized = append (symbolized , modified ... )
555+ ret = append (ret , copy )
503556 }
504- return symbolized
557+ return ret
505558}
506559
507560type parsedOpcodes struct {
0 commit comments