github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/prog/parse.go (about)

     1  // Copyright 2015 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package prog
     5  
     6  import (
     7  	"bytes"
     8  	"strconv"
     9  )
    10  
    11  // LogEntry describes one program in execution log.
    12  type LogEntry struct {
    13  	P     *Prog
    14  	Proc  int // index of parallel proc
    15  	Start int // start offset in log
    16  	End   int // end offset in log
    17  }
    18  
    19  func (target *Target) ParseLog(data []byte) []*LogEntry {
    20  	var entries []*LogEntry
    21  	ent := &LogEntry{}
    22  	var cur []byte
    23  	faultCall, faultNth := -1, -1
    24  	for pos := 0; pos < len(data); {
    25  		nl := bytes.IndexByte(data[pos:], '\n')
    26  		if nl == -1 {
    27  			nl = len(data) - 1
    28  		} else {
    29  			nl += pos
    30  		}
    31  		line := data[pos : nl+1]
    32  		pos0 := pos
    33  		pos = nl + 1
    34  
    35  		if proc, ok := extractInt(line, "executing program "); ok {
    36  			if ent.P != nil && len(ent.P.Calls) != 0 {
    37  				ent.End = pos0
    38  				entries = append(entries, ent)
    39  				faultCall, faultNth = -1, -1
    40  			}
    41  			ent = &LogEntry{
    42  				Proc:  proc,
    43  				Start: pos0,
    44  			}
    45  			// We no longer print it this way, but we still parse such fragments to preserve
    46  			// the backward compatibility.
    47  			if parsedFaultCall, ok := extractInt(line, "fault-call:"); ok {
    48  				faultCall = parsedFaultCall
    49  				faultNth, _ = extractInt(line, "fault-nth:")
    50  			}
    51  			cur = nil
    52  			continue
    53  		}
    54  
    55  		tmp := append(cur, line...)
    56  
    57  		p, err := target.Deserialize(tmp, NonStrict)
    58  		if err != nil {
    59  			continue
    60  		}
    61  
    62  		if faultCall >= 0 && faultCall < len(p.Calls) {
    63  			// We add 1 because now the property is 1-based.
    64  			p.Calls[faultCall].Props.FailNth = faultNth + 1
    65  		}
    66  
    67  		cur = tmp
    68  		ent.P = p
    69  	}
    70  	if ent.P != nil && len(ent.P.Calls) != 0 {
    71  		ent.End = len(data)
    72  		entries = append(entries, ent)
    73  	}
    74  	return entries
    75  }
    76  
    77  func extractInt(line []byte, prefix string) (int, bool) {
    78  	pos := bytes.Index(line, []byte(prefix))
    79  	if pos == -1 {
    80  		return 0, false
    81  	}
    82  	pos += len(prefix)
    83  	end := pos
    84  	for end != len(line) && line[end] >= '0' && line[end] <= '9' {
    85  		end++
    86  	}
    87  	v, _ := strconv.Atoi(string(line[pos:end]))
    88  	return v, true
    89  }