qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

libqtest: make bufwrite rely on the TransportOps

When using qtest "in-process" communication, qtest_sendf directly calls
a function in the server (qtest.c). Previously, bufwrite used
socket_send, which bypasses the TransportOps enabling the call into
qtest.c. This change replaces the socket_send calls with ops->send,
maintaining the benefits of the direct socket_send call, while adding
support for in-process qtest calls.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Message-id: 20200220041118.23264-8-alxndr@bu.edu
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>

authored by

Alexander Bulekov and committed by
Stefan Hajnoczi
ca5d4641 07533481

+73 -2
+69 -2
tests/qtest/libqtest.c
··· 37 37 38 38 39 39 typedef void (*QTestSendFn)(QTestState *s, const char *buf); 40 + typedef void (*ExternalSendFn)(void *s, const char *buf); 40 41 typedef GString* (*QTestRecvFn)(QTestState *); 41 42 42 43 typedef struct QTestClientTransportOps { 43 44 QTestSendFn send; /* for sending qtest commands */ 45 + 46 + /* 47 + * use external_send to send qtest command strings through functions which 48 + * do not accept a QTestState as the first parameter. 49 + */ 50 + ExternalSendFn external_send; 51 + 44 52 QTestRecvFn recv_line; /* for receiving qtest command responses */ 45 53 } QTestTransportOps; 46 54 ··· 1078 1086 1079 1087 bdata = g_base64_encode(data, size); 1080 1088 qtest_sendf(s, "b64write 0x%" PRIx64 " 0x%zx ", addr, size); 1081 - socket_send(s->fd, bdata, strlen(bdata)); 1082 - socket_send(s->fd, "\n", 1); 1089 + s->ops.send(s, bdata); 1090 + s->ops.send(s, "\n"); 1083 1091 qtest_rsp(s, 0); 1084 1092 g_free(bdata); 1085 1093 } ··· 1367 1375 { 1368 1376 s->ops.recv_line = recv; 1369 1377 } 1378 + /* A type-safe wrapper for s->send() */ 1379 + static void send_wrapper(QTestState *s, const char *buf) 1380 + { 1381 + s->ops.external_send(s, buf); 1382 + } 1383 + 1384 + static GString *qtest_client_inproc_recv_line(QTestState *s) 1385 + { 1386 + GString *line; 1387 + size_t offset; 1388 + char *eol; 1389 + 1390 + eol = strchr(s->rx->str, '\n'); 1391 + offset = eol - s->rx->str; 1392 + line = g_string_new_len(s->rx->str, offset); 1393 + g_string_erase(s->rx, 0, offset + 1); 1394 + return line; 1395 + } 1396 + 1397 + QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch, 1398 + void (*send)(void*, const char*)) 1399 + { 1400 + QTestState *qts; 1401 + qts = g_new0(QTestState, 1); 1402 + *s = qts; /* Expose qts early on, since the query endianness relies on it */ 1403 + qts->wstatus = 0; 1404 + for (int i = 0; i < MAX_IRQ; i++) { 1405 + qts->irq_level[i] = false; 1406 + } 1407 + 1408 + qtest_client_set_rx_handler(qts, qtest_client_inproc_recv_line); 1409 + 1410 + /* send() may not have a matching protoype, so use a type-safe wrapper */ 1411 + qts->ops.external_send = send; 1412 + qtest_client_set_tx_handler(qts, send_wrapper); 1413 + 1414 + qts->big_endian = qtest_query_target_endianness(qts); 1415 + 1416 + /* 1417 + * Set a dummy path for QTEST_QEMU_BINARY. Doesn't need to exist, but this 1418 + * way, qtest_get_arch works for inproc qtest. 1419 + */ 1420 + gchar *bin_path = g_strconcat("/qemu-system-", arch, NULL); 1421 + setenv("QTEST_QEMU_BINARY", bin_path, 0); 1422 + g_free(bin_path); 1423 + 1424 + return qts; 1425 + } 1426 + 1427 + void qtest_client_inproc_recv(void *opaque, const char *str) 1428 + { 1429 + QTestState *qts = *(QTestState **)opaque; 1430 + 1431 + if (!qts->rx) { 1432 + qts->rx = g_string_new(NULL); 1433 + } 1434 + g_string_append(qts->rx, str); 1435 + return; 1436 + }
+4
tests/qtest/libqtest.h
··· 729 729 */ 730 730 void qtest_set_expected_status(QTestState *s, int status); 731 731 732 + QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch, 733 + void (*send)(void*, const char*)); 734 + 735 + void qtest_client_inproc_recv(void *opaque, const char *str); 732 736 #endif