github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/vm/qemu/qmp.go (about)

     1  // Copyright 2020 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 qemu
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"net"
    10  
    11  	"github.com/google/syzkaller/pkg/log"
    12  )
    13  
    14  type qmpVersion struct {
    15  	Package string
    16  	QEMU    struct {
    17  		Major int
    18  		Micro int
    19  		Minor int
    20  	}
    21  }
    22  
    23  type qmpBanner struct {
    24  	QMP struct {
    25  		Version qmpVersion
    26  	}
    27  }
    28  
    29  type qmpCommand struct {
    30  	Execute   string      `json:"execute"`
    31  	Arguments interface{} `json:"arguments,omitempty"`
    32  }
    33  
    34  type hmpCommand struct {
    35  	Command string `json:"command-line"`
    36  	CPU     int    `json:"cpu-index"`
    37  }
    38  
    39  type qmpResponse struct {
    40  	Error struct {
    41  		Class string
    42  		Desc  string
    43  	}
    44  	Return interface{}
    45  
    46  	Event     string
    47  	Data      map[string]interface{}
    48  	Timestamp struct {
    49  		Seconds      int64
    50  		Microseconds int64
    51  	}
    52  }
    53  
    54  func (inst *instance) qmpConnCheck() error {
    55  	if inst.mon != nil {
    56  		return nil
    57  	}
    58  
    59  	addr := fmt.Sprintf("127.0.0.1:%v", inst.monport)
    60  	conn, err := net.Dial("tcp", addr)
    61  	if err != nil {
    62  		return err
    63  	}
    64  
    65  	monDec := json.NewDecoder(conn)
    66  	monEnc := json.NewEncoder(conn)
    67  
    68  	var banner qmpBanner
    69  	if err := monDec.Decode(&banner); err != nil {
    70  		return err
    71  	}
    72  
    73  	inst.monEnc = monEnc
    74  	inst.monDec = monDec
    75  	if _, err := inst.doQmp(&qmpCommand{Execute: "qmp_capabilities"}); err != nil {
    76  		inst.monEnc = nil
    77  		inst.monDec = nil
    78  		return err
    79  	}
    80  	inst.mon = conn
    81  
    82  	return nil
    83  }
    84  
    85  func (inst *instance) qmpRecv() (*qmpResponse, error) {
    86  	for {
    87  		qmp := new(qmpResponse)
    88  		err := inst.monDec.Decode(qmp)
    89  		if err != nil || qmp.Event == "" {
    90  			return qmp, err
    91  		}
    92  		log.Logf(1, "event: %v", qmp)
    93  	}
    94  }
    95  
    96  func (inst *instance) doQmp(cmd *qmpCommand) (*qmpResponse, error) {
    97  	if err := inst.monEnc.Encode(cmd); err != nil {
    98  		return nil, err
    99  	}
   100  	return inst.qmpRecv()
   101  }
   102  
   103  func (inst *instance) qmp(cmd *qmpCommand) (interface{}, error) {
   104  	if err := inst.qmpConnCheck(); err != nil {
   105  		return nil, err
   106  	}
   107  	resp, err := inst.doQmp(cmd)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	if resp.Error.Desc != "" {
   112  		return nil, fmt.Errorf("error %v", resp.Error)
   113  	}
   114  	if resp.Return == nil {
   115  		return nil, fmt.Errorf(`no "return" nor "error" in [%v]`, resp)
   116  	}
   117  	return resp.Return, nil
   118  }
   119  
   120  func (inst *instance) hmp(cmd string, cpu int) (string, error) {
   121  	req := &qmpCommand{
   122  		Execute: "human-monitor-command",
   123  		Arguments: &hmpCommand{
   124  			Command: cmd,
   125  			CPU:     cpu,
   126  		},
   127  	}
   128  	resp, err := inst.qmp(req)
   129  	if err != nil {
   130  		return "", err
   131  	}
   132  	return resp.(string), nil
   133  }