github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/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  	ID    int // ID of the executed program (-1 if not present)
    16  	Start int // start offset in log
    17  	End   int // end offset in log
    18  }
    19  
    20  func (target *Target) ParseLog(data []byte, mode DeserializeMode) []*LogEntry {
    21  	var entries []*LogEntry
    22  	ent := &LogEntry{
    23  		ID: -1,
    24  	}
    25  	var cur []byte
    26  	faultCall, faultNth := -1, -1
    27  	for pos := 0; pos < len(data); {
    28  		nl := bytes.IndexByte(data[pos:], '\n')
    29  		if nl == -1 {
    30  			nl = len(data) - 1
    31  		} else {
    32  			nl += pos
    33  		}
    34  		line := data[pos : nl+1]
    35  		pos0 := pos
    36  		pos = nl + 1
    37  
    38  		if proc, ok := extractInt(line, "executing program "); ok {
    39  			if ent.P != nil && len(ent.P.Calls) != 0 {
    40  				ent.End = pos0
    41  				entries = append(entries, ent)
    42  				faultCall, faultNth = -1, -1
    43  			}
    44  			ent = &LogEntry{
    45  				Proc:  proc,
    46  				Start: pos0,
    47  				ID:    -1,
    48  			}
    49  			if id, ok := extractInt(line, "id="); ok {
    50  				ent.ID = id
    51  			}
    52  			// We no longer print it this way, but we still parse such fragments to preserve
    53  			// the backward compatibility.
    54  			if parsedFaultCall, ok := extractInt(line, "fault-call:"); ok {
    55  				faultCall = parsedFaultCall
    56  				faultNth, _ = extractInt(line, "fault-nth:")
    57  			}
    58  			cur = nil
    59  			continue
    60  		}
    61  
    62  		tmp := append(cur, line...)
    63  
    64  		p, err := target.Deserialize(tmp, mode)
    65  		if err != nil {
    66  			continue
    67  		}
    68  
    69  		if faultCall >= 0 && faultCall < len(p.Calls) {
    70  			// We add 1 because now the property is 1-based.
    71  			p.Calls[faultCall].Props.FailNth = faultNth + 1
    72  		}
    73  
    74  		cur = tmp
    75  		ent.P = p
    76  	}
    77  	if ent.P != nil && len(ent.P.Calls) != 0 {
    78  		ent.End = len(data)
    79  		entries = append(entries, ent)
    80  	}
    81  	return entries
    82  }
    83  
    84  func extractInt(line []byte, prefix string) (int, bool) {
    85  	pos := bytes.Index(line, []byte(prefix))
    86  	if pos == -1 {
    87  		return 0, false
    88  	}
    89  	pos += len(prefix)
    90  	end := pos
    91  	for end != len(line) && line[end] >= '0' && line[end] <= '9' {
    92  		end++
    93  	}
    94  	v, _ := strconv.Atoi(string(line[pos:end]))
    95  	return v, true
    96  }