* [PATCH BlueZ v1 0/6] monitor: Search the frames with a pager
@ 2026-09-17 20:45 Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 1/6] monitor: Route the decoding output through a single function Luiz Augusto von Dentz
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-17 20:45 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
A frame spans several lines, and what identifies one is spread between
its header and its contents: the header says which controller and when,
the body says what happened. Searching a trace a line at a time finds the
line reporting an error without any of that context.
This series makes the frames searchable as whole entries:
$ btmon # then press Ctrl-R
$ btmon -r hcidump.log
$ btmon -r hcidump.log --print0 | fzf --read0
Patch 1 sends the decoding output through one function so that a frame
can be observed as a whole. It is a pure redirection and the output is
unchanged.
Patch 2 separates the frames with a NUL when something is going to read
them as records, asked for by --print0 or by --read0 already being in
PAGER. Nothing is separated otherwise, so a pager reading lines and
redirected output are both untouched.
Patches 3 and 4 hand the frames seen so far to the pager on Ctrl-R while
capturing. The capture is never paused for this, as anything not read in
time is dropped by the kernel, and whatever arrives while the pager is up
is printed once it closes so the trace on the terminal has no gap.
Patches 5 and 6 use fzf when PAGER is not set and it is installed, since
it suits a trace far better than a plain pager, giving it --ansi and
--read0 wherever it is used.
Luiz Augusto von Dentz (6):
monitor: Route the decoding output through a single function
monitor: Separate the frames for a pager reading records
monitor: Hand the captured frames to the pager on Ctrl-R
doc/btmon: Document searching the frames
monitor: Prefer fzf as the pager when one is not set
doc/btmon: Document the pager choice
Makefile.tools | 1 +
doc/btmon.rst | 64 ++++++
monitor/analyze.c | 44 ++--
monitor/avctp.c | 68 +++----
monitor/control.c | 163 ++++++++-------
monitor/display.c | 93 ++++++++-
monitor/display.h | 14 +-
monitor/find.c | 499 ++++++++++++++++++++++++++++++++++++++++++++++
monitor/find.h | 19 ++
monitor/l2cap.c | 34 ++--
monitor/lmp.c | 4 +-
monitor/main.c | 28 ++-
monitor/packet.c | 18 +-
monitor/rfcomm.c | 6 +-
tools/l2test.c | 10 +
15 files changed, 891 insertions(+), 174 deletions(-)
create mode 100644 monitor/find.c
create mode 100644 monitor/find.h
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH BlueZ v1 1/6] monitor: Route the decoding output through a single function
2026-09-17 20:45 [PATCH BlueZ v1 0/6] monitor: Search the frames with a pager Luiz Augusto von Dentz
@ 2026-09-17 20:45 ` Luiz Augusto von Dentz
2026-09-17 23:55 ` monitor: Search the frames with a pager bluez.test.bot
2026-09-17 20:45 ` [PATCH BlueZ v1 2/6] monitor: Separate the frames for a pager reading records Luiz Augusto von Dentz
` (4 subsequent siblings)
5 siblings, 1 reply; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-17 20:45 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
The decoding output is written straight to stdout, partly through the
print_indent() macro and partly through some 167 direct printf() calls,
several of which build a single line across multiple calls. There is no
point at which the output of a frame can be observed as a whole.
Send all of it through display_printf(), which writes to a redirectable
stream, so that a caller can capture a frame and decide what to do with
it rather than having it go straight to the terminal. Capturing at the
stream level keeps the partially built lines working without having to
find and restructure them.
This is a pure redirection and the output is unchanged. The messages
jlink emits while connecting are left alone, as they are not part of the
decoding.
l2test uses the printing helpers from the header without linking the
monitor, so it gains its own display_printf() next to the use_color() it
already defines for the same reason.
The model performed the conversion, which the author reviewed and
verified by comparing the output of both modes over a set of traces
before and after, byte for byte.
Assisted-by: opencode:claude-opus-5
---
monitor/analyze.c | 44 +++++++-------
monitor/avctp.c | 68 ++++++++++-----------
monitor/control.c | 148 +++++++++++++++++++++++-----------------------
monitor/display.c | 20 +++++++
monitor/display.h | 11 +++-
monitor/l2cap.c | 34 +++++------
monitor/lmp.c | 4 +-
monitor/main.c | 12 ++--
monitor/packet.c | 18 +++---
monitor/rfcomm.c | 6 +-
tools/l2test.c | 10 ++++
11 files changed, 207 insertions(+), 168 deletions(-)
diff --git a/monitor/analyze.c b/monitor/analyze.c
index 154303eb7330..fcd13dce8fdd 100644
--- a/monitor/analyze.c
+++ b/monitor/analyze.c
@@ -277,11 +277,11 @@ static void chan_destroy(void *data)
fixed = fixed_channel_name(chan->cid);
if (fixed)
- printf(" Found %s L2CAP channel with CID %u (%s)\n",
+ display_printf(" Found %s L2CAP channel with CID %u (%s)\n",
chan->out ? "TX" : "RX", chan->cid,
fixed);
else
- printf(" Found %s L2CAP channel with CID %u\n",
+ display_printf(" Found %s L2CAP channel with CID %u\n",
chan->out ? "TX" : "RX", chan->cid);
if (chan->psm)
@@ -370,7 +370,7 @@ static void conn_destroy(void *data)
break;
}
- printf(" Found %s connection with handle %u\n", str, conn->handle);
+ display_printf(" Found %s connection with handle %u\n", str, conn->handle);
packet_print_addr("Address", conn->bdaddr, conn->bdaddr_type);
if (!conn->setup_seen)
print_field("Connection setup missing");
@@ -482,29 +482,29 @@ static void dev_destroy(void *data)
break;
}
- printf("Found %s controller with index %u\n", str, dev->index);
- printf(" BD_ADDR %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ display_printf("Found %s controller with index %u\n", str, dev->index);
+ display_printf(" BD_ADDR %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
dev->bdaddr[5], dev->bdaddr[4], dev->bdaddr[3],
dev->bdaddr[2], dev->bdaddr[1], dev->bdaddr[0]);
if (dev->manufacturer != 0xffff)
- printf(" (%s)", bt_compidtostr(dev->manufacturer));
- printf("\n");
+ display_printf(" (%s)", bt_compidtostr(dev->manufacturer));
+ display_printf("\n");
- printf(" %lu commands\n", dev->num_cmd);
- printf(" %lu events\n", dev->num_evt);
- printf(" %lu ACL packets\n", dev->num_acl);
- printf(" %lu SCO packets\n", dev->num_sco);
- printf(" %lu ISO packets\n", dev->num_iso);
- printf(" %lu vendor packets\n", dev->num_vendor);
- printf(" %lu vendor diagnostics\n", dev->vendor_diag);
- printf(" %lu system notes\n", dev->system_note);
- printf(" %lu user logs\n", dev->user_log);
- printf(" %lu control messages \n", dev->ctrl_msg);
- printf(" %lu unknown opcodes\n", dev->unknown);
+ display_printf(" %lu commands\n", dev->num_cmd);
+ display_printf(" %lu events\n", dev->num_evt);
+ display_printf(" %lu ACL packets\n", dev->num_acl);
+ display_printf(" %lu SCO packets\n", dev->num_sco);
+ display_printf(" %lu ISO packets\n", dev->num_iso);
+ display_printf(" %lu vendor packets\n", dev->num_vendor);
+ display_printf(" %lu vendor diagnostics\n", dev->vendor_diag);
+ display_printf(" %lu system notes\n", dev->system_note);
+ display_printf(" %lu user logs\n", dev->user_log);
+ display_printf(" %lu control messages \n", dev->ctrl_msg);
+ display_printf(" %lu unknown opcodes\n", dev->unknown);
if (dev->num_cmd_rsp)
- printf(" Command latency: %lld-%lld msec "
+ display_printf(" Command latency: %lld-%lld msec "
"(~%lld msec +/- %lld msec)\n",
TV_MSEC(dev->cmd_latency.min),
TV_MSEC(dev->cmd_latency.max),
@@ -513,12 +513,12 @@ static void dev_destroy(void *data)
/* Whatever is left never got a Command Complete or Command Status */
if (!queue_isempty(dev->cmd_list))
- printf(" Commands without response: %u\n",
+ display_printf(" Commands without response: %u\n",
queue_length(dev->cmd_list));
queue_destroy(dev->cmd_list, free);
queue_destroy(dev->conn_list, conn_destroy);
- printf("\n");
+ display_printf("\n");
free(dev);
}
@@ -1639,7 +1639,7 @@ void analyze_trace(const char *path)
num_packets++;
}
- printf("Trace contains %lu packets\n\n", num_packets);
+ display_printf("Trace contains %lu packets\n\n", num_packets);
queue_destroy(dev_list, dev_destroy);
diff --git a/monitor/avctp.c b/monitor/avctp.c
index 75afaca8342f..d6eb603d2905 100644
--- a/monitor/avctp.c
+++ b/monitor/avctp.c
@@ -1049,16 +1049,16 @@ response:
print_field("%*cStringLength: 0x%02x", (indent - 8), ' ', len);
- printf("String: ");
+ display_printf("String: ");
for (; len > 0; len--) {
uint8_t c;
if (!l2cap_frame_get_u8(frame, &c))
return false;
- printf("%1c", isprint(c) ? c : '.');
+ display_printf("%1c", isprint(c) ? c : '.');
}
- printf("\n");
+ display_printf("\n");
}
return true;
@@ -1125,16 +1125,16 @@ response:
print_field("%*cStringLength: 0x%02x", (indent - 8), ' ', len);
- printf("String: ");
+ display_printf("String: ");
for (; len > 0; len--) {
uint8_t c;
if (!l2cap_frame_get_u8(frame, &c))
return false;
- printf("%1c", isprint(c) ? c : '.');
+ display_printf("%1c", isprint(c) ? c : '.');
}
- printf("\n");
+ display_printf("\n");
}
return true;
@@ -1405,16 +1405,16 @@ response:
' ', status);
switch (status) {
case 0x00:
- printf("(POWER_ON)\n");
+ display_printf("(POWER_ON)\n");
break;
case 0x01:
- printf("(POWER_OFF)\n");
+ display_printf("(POWER_OFF)\n");
break;
case 0x02:
- printf("(UNPLUGGED)\n");
+ display_printf("(UNPLUGGED)\n");
break;
default:
- printf("(UNKNOWN)\n");
+ display_printf("(UNKNOWN)\n");
break;
}
break;
@@ -1873,16 +1873,16 @@ static bool avrcp_media_player_item(struct avctp_frame *avctp_frame,
print_field("%*cPlayStatus: 0x%02x (%s)", indent, ' ',
status, playstatus2str(status));
- printf("%*cFeatures: 0x", indent+8, ' ');
+ display_printf("%*cFeatures: 0x", indent+8, ' ');
for (i = 0; i < 16; i++) {
if (!l2cap_frame_get_u8(frame, &features[i]))
return false;
- printf("%02x", features[i]);
+ display_printf("%02x", features[i]);
}
- printf("\n");
+ display_printf("\n");
print_features(features, indent + 2);
@@ -1898,15 +1898,15 @@ static bool avrcp_media_player_item(struct avctp_frame *avctp_frame,
print_field("%*cNameLength: 0x%04x (%u)", indent, ' ',
namelen, namelen);
- printf("%*cName: ", indent+8, ' ');
+ display_printf("%*cName: ", indent+8, ' ');
for (; namelen > 0; namelen--) {
uint8_t c;
if (!l2cap_frame_get_u8(frame, &c))
return false;
- printf("%1c", isprint(c) ? c : '.');
+ display_printf("%1c", isprint(c) ? c : '.');
}
- printf("\n");
+ display_printf("\n");
return true;
}
@@ -1920,7 +1920,7 @@ static bool avrcp_folder_item(struct avctp_frame *avctp_frame,
uint64_t uid;
if (frame->size < 14) {
- printf("PDU Malformed\n");
+ display_printf("PDU Malformed\n");
return false;
}
@@ -1954,15 +1954,15 @@ static bool avrcp_folder_item(struct avctp_frame *avctp_frame,
print_field("%*cNameLength: 0x%04x (%u)", indent, ' ',
namelen, namelen);
- printf("%*cName: ", indent+8, ' ');
+ display_printf("%*cName: ", indent+8, ' ');
for (; namelen > 0; namelen--) {
uint8_t c;
if (!l2cap_frame_get_u8(frame, &c))
return false;
- printf("%1c", isprint(c) ? c : '.');
+ display_printf("%1c", isprint(c) ? c : '.');
}
- printf("\n");
+ display_printf("\n");
return true;
}
@@ -1994,16 +1994,16 @@ static bool avrcp_attribute_entry_list(struct avctp_frame *avctp_frame,
print_field("%*cAttributeLength: 0x%04x (%u)", indent, ' ',
len, len);
- printf("%*cAttributeValue: ", indent+8, ' ');
+ display_printf("%*cAttributeValue: ", indent+8, ' ');
for (; len > 0; len--) {
uint8_t c;
if (!l2cap_frame_get_u8(frame, &c))
return false;
- printf("%1c", isprint(c) ? c : '.');
+ display_printf("%1c", isprint(c) ? c : '.');
}
- printf("\n");
+ display_printf("\n");
}
return true;
@@ -2041,15 +2041,15 @@ static bool avrcp_media_element_item(struct avctp_frame *avctp_frame,
print_field("%*cNameLength: 0x%04x (%u)", indent, ' ',
namelen, namelen);
- printf("%*cName: ", indent+8, ' ');
+ display_printf("%*cName: ", indent+8, ' ');
for (; namelen > 0; namelen--) {
uint8_t c;
if (!l2cap_frame_get_u8(frame, &c))
return false;
- printf("%1c", isprint(c) ? c : '.');
+ display_printf("%1c", isprint(c) ? c : '.');
}
- printf("\n");
+ display_printf("\n");
if (!l2cap_frame_get_u8(frame, &count))
return false;
@@ -2097,7 +2097,7 @@ static bool avrcp_get_total_number_of_items(struct avctp_frame *avctp_frame)
goto response;
if (frame->size < 4) {
- printf("PDU Malformed\n");
+ display_printf("PDU Malformed\n");
packet_hexdump(frame->data, frame->size);
return false;
}
@@ -2146,7 +2146,7 @@ static bool avrcp_search_item(struct avctp_frame *avctp_frame)
goto response;
if (frame->size < 4) {
- printf("PDU Malformed\n");
+ display_printf("PDU Malformed\n");
packet_hexdump(frame->data, frame->size);
return false;
}
@@ -2162,17 +2162,17 @@ static bool avrcp_search_item(struct avctp_frame *avctp_frame)
print_field("%*cLength: 0x%04x (%u)", indent, ' ', namelen, namelen);
- printf("%*cString: ", indent+8, ' ');
+ display_printf("%*cString: ", indent+8, ' ');
for (; namelen > 0; namelen--) {
uint8_t c;
if (!l2cap_frame_get_u8(frame, &c))
return false;
- printf("%1c", isprint(c) ? c : '.');
+ display_printf("%1c", isprint(c) ? c : '.');
}
- printf("\n");
+ display_printf("\n");
return true;
@@ -2426,16 +2426,16 @@ response:
continue;
}
- printf("%*cFolder: ", indent+8, ' ');
+ display_printf("%*cFolder: ", indent+8, ' ');
for (; len > 0; len--) {
uint8_t c;
if (!l2cap_frame_get_u8(frame, &c))
return false;
- printf("%1c", isprint(c) ? c : '.');
+ display_printf("%1c", isprint(c) ? c : '.');
}
- printf("\n");
+ display_printf("\n");
}
return true;
diff --git a/monitor/control.c b/monitor/control.c
index 1eab9c4fe0bd..8ed221e08a02 100644
--- a/monitor/control.c
+++ b/monitor/control.c
@@ -69,28 +69,28 @@ static void free_data(void *user_data)
static void mgmt_index_added(uint16_t len, const void *buf)
{
- printf("@ Index Added\n");
+ display_printf("@ Index Added\n");
packet_hexdump(buf, len);
}
static void mgmt_index_removed(uint16_t len, const void *buf)
{
- printf("@ Index Removed\n");
+ display_printf("@ Index Removed\n");
packet_hexdump(buf, len);
}
static void mgmt_unconf_index_added(uint16_t len, const void *buf)
{
- printf("@ Unconfigured Index Added\n");
+ display_printf("@ Unconfigured Index Added\n");
packet_hexdump(buf, len);
}
static void mgmt_unconf_index_removed(uint16_t len, const void *buf)
{
- printf("@ Unconfigured Index Removed\n");
+ display_printf("@ Unconfigured Index Removed\n");
packet_hexdump(buf, len);
}
@@ -100,11 +100,11 @@ static void mgmt_ext_index_added(uint16_t len, const void *buf)
const struct mgmt_ev_ext_index_added *ev = buf;
if (len < sizeof(*ev)) {
- printf("* Malformed Extended Index Added control\n");
+ display_printf("* Malformed Extended Index Added control\n");
return;
}
- printf("@ Extended Index Added: %u (%u)\n", ev->type, ev->bus);
+ display_printf("@ Extended Index Added: %u (%u)\n", ev->type, ev->bus);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -117,11 +117,11 @@ static void mgmt_ext_index_removed(uint16_t len, const void *buf)
const struct mgmt_ev_ext_index_removed *ev = buf;
if (len < sizeof(*ev)) {
- printf("* Malformed Extended Index Removed control\n");
+ display_printf("* Malformed Extended Index Removed control\n");
return;
}
- printf("@ Extended Index Removed: %u (%u)\n", ev->type, ev->bus);
+ display_printf("@ Extended Index Removed: %u (%u)\n", ev->type, ev->bus);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -134,11 +134,11 @@ static void mgmt_controller_error(uint16_t len, const void *buf)
const struct mgmt_ev_controller_error *ev = buf;
if (len < sizeof(*ev)) {
- printf("* Malformed Controller Error control\n");
+ display_printf("* Malformed Controller Error control\n");
return;
}
- printf("@ Controller Error: 0x%2.2x\n", ev->error_code);
+ display_printf("@ Controller Error: 0x%2.2x\n", ev->error_code);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -160,21 +160,21 @@ static void mgmt_new_config_options(uint16_t len, const void *buf)
unsigned int i;
if (len < 4) {
- printf("* Malformed New Configuration Options control\n");
+ display_printf("* Malformed New Configuration Options control\n");
return;
}
options = get_le32(buf);
- printf("@ New Configuration Options: 0x%4.4x\n", options);
+ display_printf("@ New Configuration Options: 0x%4.4x\n", options);
if (options) {
- printf("%-12c", ' ');
+ display_printf("%-12c", ' ');
for (i = 0; i < NELEM(config_options_str); i++) {
if (options & (1 << i))
- printf("%s ", config_options_str[i]);
+ display_printf("%s ", config_options_str[i]);
}
- printf("\n");
+ display_printf("\n");
}
buf += 4;
@@ -196,21 +196,21 @@ static void mgmt_new_settings(uint16_t len, const void *buf)
unsigned int i;
if (len < 4) {
- printf("* Malformed New Settings control\n");
+ display_printf("* Malformed New Settings control\n");
return;
}
settings = get_le32(buf);
- printf("@ New Settings: 0x%4.4x\n", settings);
+ display_printf("@ New Settings: 0x%4.4x\n", settings);
if (settings) {
- printf("%-12c", ' ');
+ display_printf("%-12c", ' ');
for (i = 0; i < NELEM(settings_str); i++) {
if (settings & (1 << i))
- printf("%s ", settings_str[i]);
+ display_printf("%s ", settings_str[i]);
}
- printf("\n");
+ display_printf("\n");
}
buf += 4;
@@ -224,11 +224,11 @@ static void mgmt_class_of_dev_changed(uint16_t len, const void *buf)
const struct mgmt_ev_class_of_dev_changed *ev = buf;
if (len < sizeof(*ev)) {
- printf("* Malformed Class of Device Changed control\n");
+ display_printf("* Malformed Class of Device Changed control\n");
return;
}
- printf("@ Class of Device Changed: 0x%2.2x%2.2x%2.2x\n",
+ display_printf("@ Class of Device Changed: 0x%2.2x%2.2x%2.2x\n",
ev->dev_class[2],
ev->dev_class[1],
ev->dev_class[0]);
@@ -244,11 +244,11 @@ static void mgmt_local_name_changed(uint16_t len, const void *buf)
const struct mgmt_ev_local_name_changed *ev = buf;
if (len < sizeof(*ev)) {
- printf("* Malformed Local Name Changed control\n");
+ display_printf("* Malformed Local Name Changed control\n");
return;
}
- printf("@ Local Name Changed: %s (%s)\n", ev->name, ev->short_name);
+ display_printf("@ Local Name Changed: %s (%s)\n", ev->name, ev->short_name);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -274,7 +274,7 @@ static void mgmt_new_link_key(uint16_t len, const void *buf)
};
if (len < sizeof(*ev)) {
- printf("* Malformed New Link Key control\n");
+ display_printf("* Malformed New Link Key control\n");
return;
}
@@ -285,7 +285,7 @@ static void mgmt_new_link_key(uint16_t len, const void *buf)
ba2str(&ev->key.addr.bdaddr, str);
- printf("@ New Link Key: %s (%d) %s (%u)\n", str,
+ display_printf("@ New Link Key: %s (%d) %s (%u)\n", str,
ev->key.addr.type, type, ev->key.type);
buf += sizeof(*ev);
@@ -301,7 +301,7 @@ static void mgmt_new_long_term_key(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed New Long Term Key control\n");
+ display_printf("* Malformed New Long Term Key control\n");
return;
}
@@ -335,7 +335,7 @@ static void mgmt_new_long_term_key(uint16_t len, const void *buf)
ba2str(&ev->key.addr.bdaddr, str);
- printf("@ New Long Term Key: %s (%d) %s 0x%02x\n", str,
+ display_printf("@ New Long Term Key: %s (%d) %s 0x%02x\n", str,
ev->key.addr.type, type, ev->key.type);
buf += sizeof(*ev);
@@ -351,14 +351,14 @@ static void mgmt_device_connected(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed Device Connected control\n");
+ display_printf("* Malformed Device Connected control\n");
return;
}
flags = le32_to_cpu(ev->flags);
ba2str(&ev->addr.bdaddr, str);
- printf("@ Device Connected: %s (%d) flags 0x%4.4x\n",
+ display_printf("@ Device Connected: %s (%d) flags 0x%4.4x\n",
str, ev->addr.type, flags);
buf += sizeof(*ev);
@@ -375,7 +375,7 @@ static void mgmt_device_disconnected(uint16_t len, const void *buf)
uint16_t consumed_len;
if (len < sizeof(struct mgmt_addr_info)) {
- printf("* Malformed Device Disconnected control\n");
+ display_printf("* Malformed Device Disconnected control\n");
return;
}
@@ -389,7 +389,7 @@ static void mgmt_device_disconnected(uint16_t len, const void *buf)
ba2str(&ev->addr.bdaddr, str);
- printf("@ Device Disconnected: %s (%d) reason %u\n", str, ev->addr.type,
+ display_printf("@ Device Disconnected: %s (%d) reason %u\n", str, ev->addr.type,
reason);
buf += consumed_len;
@@ -404,13 +404,13 @@ static void mgmt_connect_failed(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed Connect Failed control\n");
+ display_printf("* Malformed Connect Failed control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
- printf("@ Connect Failed: %s (%d) status 0x%2.2x\n",
+ display_printf("@ Connect Failed: %s (%d) status 0x%2.2x\n",
str, ev->addr.type, ev->status);
buf += sizeof(*ev);
@@ -425,13 +425,13 @@ static void mgmt_pin_code_request(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed PIN Code Request control\n");
+ display_printf("* Malformed PIN Code Request control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
- printf("@ PIN Code Request: %s (%d) secure 0x%2.2x\n",
+ display_printf("@ PIN Code Request: %s (%d) secure 0x%2.2x\n",
str, ev->addr.type, ev->secure);
buf += sizeof(*ev);
@@ -446,13 +446,13 @@ static void mgmt_user_confirm_request(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed User Confirmation Request control\n");
+ display_printf("* Malformed User Confirmation Request control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
- printf("@ User Confirmation Request: %s (%d) hint %d value %d\n",
+ display_printf("@ User Confirmation Request: %s (%d) hint %d value %d\n",
str, ev->addr.type, ev->confirm_hint, ev->value);
buf += sizeof(*ev);
@@ -467,13 +467,13 @@ static void mgmt_user_passkey_request(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed User Passkey Request control\n");
+ display_printf("* Malformed User Passkey Request control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
- printf("@ User Passkey Request: %s (%d)\n", str, ev->addr.type);
+ display_printf("@ User Passkey Request: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -487,13 +487,13 @@ static void mgmt_auth_failed(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed Authentication Failed control\n");
+ display_printf("* Malformed Authentication Failed control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
- printf("@ Authentication Failed: %s (%d) status 0x%2.2x\n",
+ display_printf("@ Authentication Failed: %s (%d) status 0x%2.2x\n",
str, ev->addr.type, ev->status);
buf += sizeof(*ev);
@@ -509,14 +509,14 @@ static void mgmt_device_found(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed Device Found control\n");
+ display_printf("* Malformed Device Found control\n");
return;
}
flags = le32_to_cpu(ev->flags);
ba2str(&ev->addr.bdaddr, str);
- printf("@ Device Found: %s (%d) rssi %d flags 0x%4.4x\n",
+ display_printf("@ Device Found: %s (%d) rssi %d flags 0x%4.4x\n",
str, ev->addr.type, ev->rssi, flags);
buf += sizeof(*ev);
@@ -530,11 +530,11 @@ static void mgmt_discovering(uint16_t len, const void *buf)
const struct mgmt_ev_discovering *ev = buf;
if (len < sizeof(*ev)) {
- printf("* Malformed Discovering control\n");
+ display_printf("* Malformed Discovering control\n");
return;
}
- printf("@ Discovering: 0x%2.2x (%d)\n", ev->discovering, ev->type);
+ display_printf("@ Discovering: 0x%2.2x (%d)\n", ev->discovering, ev->type);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -548,13 +548,13 @@ static void mgmt_device_blocked(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed Device Blocked control\n");
+ display_printf("* Malformed Device Blocked control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
- printf("@ Device Blocked: %s (%d)\n", str, ev->addr.type);
+ display_printf("@ Device Blocked: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -568,13 +568,13 @@ static void mgmt_device_unblocked(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed Device Unblocked control\n");
+ display_printf("* Malformed Device Unblocked control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
- printf("@ Device Unblocked: %s (%d)\n", str, ev->addr.type);
+ display_printf("@ Device Unblocked: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -588,13 +588,13 @@ static void mgmt_device_unpaired(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed Device Unpaired control\n");
+ display_printf("* Malformed Device Unpaired control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
- printf("@ Device Unpaired: %s (%d)\n", str, ev->addr.type);
+ display_printf("@ Device Unpaired: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -609,7 +609,7 @@ static void mgmt_passkey_notify(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed Passkey Notify control\n");
+ display_printf("* Malformed Passkey Notify control\n");
return;
}
@@ -617,7 +617,7 @@ static void mgmt_passkey_notify(uint16_t len, const void *buf)
passkey = le32_to_cpu(ev->passkey);
- printf("@ Passkey Notify: %s (%d) passkey %06u entered %u\n",
+ display_printf("@ Passkey Notify: %s (%d) passkey %06u entered %u\n",
str, ev->addr.type, passkey, ev->entered);
buf += sizeof(*ev);
@@ -632,14 +632,14 @@ static void mgmt_new_irk(uint16_t len, const void *buf)
char addr[18], rpa[18];
if (len < sizeof(*ev)) {
- printf("* Malformed New IRK control\n");
+ display_printf("* Malformed New IRK control\n");
return;
}
ba2str(&ev->rpa, rpa);
ba2str(&ev->key.addr.bdaddr, addr);
- printf("@ New IRK: %s (%d) %s\n", addr, ev->key.addr.type, rpa);
+ display_printf("@ New IRK: %s (%d) %s\n", addr, ev->key.addr.type, rpa);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -654,7 +654,7 @@ static void mgmt_new_csrk(uint16_t len, const void *buf)
char addr[18];
if (len < sizeof(*ev)) {
- printf("* Malformed New CSRK control\n");
+ display_printf("* Malformed New CSRK control\n");
return;
}
@@ -678,7 +678,7 @@ static void mgmt_new_csrk(uint16_t len, const void *buf)
break;
}
- printf("@ New CSRK: %s (%d) %s (%u)\n", addr, ev->key.addr.type,
+ display_printf("@ New CSRK: %s (%d) %s (%u)\n", addr, ev->key.addr.type,
type, ev->key.type);
buf += sizeof(*ev);
@@ -693,13 +693,13 @@ static void mgmt_device_added(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed Device Added control\n");
+ display_printf("* Malformed Device Added control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
- printf("@ Device Added: %s (%d) %d\n", str, ev->addr.type, ev->action);
+ display_printf("@ Device Added: %s (%d) %d\n", str, ev->addr.type, ev->action);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -713,13 +713,13 @@ static void mgmt_device_removed(uint16_t len, const void *buf)
char str[18];
if (len < sizeof(*ev)) {
- printf("* Malformed Device Removed control\n");
+ display_printf("* Malformed Device Removed control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
- printf("@ Device Removed: %s (%d)\n", str, ev->addr.type);
+ display_printf("@ Device Removed: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -734,7 +734,7 @@ static void mgmt_new_conn_param(uint16_t len, const void *buf)
uint16_t min, max, latency, timeout;
if (len < sizeof(*ev)) {
- printf("* Malformed New Connection Parameter control\n");
+ display_printf("* Malformed New Connection Parameter control\n");
return;
}
@@ -744,7 +744,7 @@ static void mgmt_new_conn_param(uint16_t len, const void *buf)
latency = le16_to_cpu(ev->latency);
timeout = le16_to_cpu(ev->timeout);
- printf("@ New Conn Param: %s (%d) hint %d min 0x%4.4x max 0x%4.4x "
+ display_printf("@ New Conn Param: %s (%d) hint %d min 0x%4.4x max 0x%4.4x "
"latency 0x%4.4x timeout 0x%4.4x\n", addr, ev->addr.type,
ev->store_hint, min, max, latency, timeout);
@@ -759,11 +759,11 @@ static void mgmt_advertising_added(uint16_t len, const void *buf)
const struct mgmt_ev_advertising_added *ev = buf;
if (len < sizeof(*ev)) {
- printf("* Malformed Advertising Added control\n");
+ display_printf("* Malformed Advertising Added control\n");
return;
}
- printf("@ Advertising Added: %u\n", ev->instance);
+ display_printf("@ Advertising Added: %u\n", ev->instance);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -776,11 +776,11 @@ static void mgmt_advertising_removed(uint16_t len, const void *buf)
const struct mgmt_ev_advertising_removed *ev = buf;
if (len < sizeof(*ev)) {
- printf("* Malformed Advertising Removed control\n");
+ display_printf("* Malformed Advertising Removed control\n");
return;
}
- printf("@ Advertising Removed: %u\n", ev->instance);
+ display_printf("@ Advertising Removed: %u\n", ev->instance);
buf += sizeof(*ev);
len -= sizeof(*ev);
@@ -894,7 +894,7 @@ void control_message(uint16_t opcode, const void *data, uint16_t size)
mgmt_advertising_removed(size, data);
break;
default:
- printf("* Unknown control (code %d len %d)\n", opcode, size);
+ display_printf("* Unknown control (code %d len %d)\n", opcode, size);
packet_hexdump(data, size);
break;
}
@@ -1200,7 +1200,7 @@ static void server_accept_callback(int fd, uint32_t events, void *user_data)
return;
}
- printf("--- New monitor connection ---\n");
+ display_printf("--- New monitor connection ---\n");
data = malloc(sizeof(*data));
if (!data) {
@@ -1339,14 +1339,14 @@ static bool tty_parse_header(uint8_t *hdr, uint8_t len, struct timeval **tv,
*tv = ctv;
break;
default:
- printf("Unknown extended header type %u\n", type);
+ display_printf("Unknown extended header type %u\n", type);
return false;
}
}
if (total) {
*drops += total;
- printf("* Drops: cmd %u evt %u acl_tx %u acl_rx %u sco_tx %u "
+ display_printf("* Drops: cmd %u evt %u acl_tx %u acl_rx %u sco_tx %u "
"sco_rx %u other %u\n", cmd, evt, acl_tx, acl_rx,
sco_tx, sco_rx, other);
}
@@ -1453,7 +1453,7 @@ int control_tty(const char *path, unsigned int speed)
return err;
}
- printf("--- %s opened ---\n", path);
+ display_printf("--- %s opened ---\n", path);
data = malloc(sizeof(*data));
if (!data) {
@@ -1510,7 +1510,7 @@ int control_rtt(char *jlink, char *rtt)
return -ENODEV;
}
- printf("--- RTT opened ---\n");
+ display_printf("--- RTT opened ---\n");
data = new0(struct control_data, 1);
data->channel = HCI_CHANNEL_MONITOR;
diff --git a/monitor/display.c b/monitor/display.c
index d61a79a383f5..b540155319a0 100644
--- a/monitor/display.c
+++ b/monitor/display.c
@@ -15,6 +15,7 @@
#define _GNU_SOURCE
#include <stdio.h>
+#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
@@ -28,6 +29,25 @@
#include "display.h"
static pid_t pager_pid = 0;
+static FILE *display_out = NULL;
+
+/*
+ * Redirect the decoding output, so that a caller can capture a frame and
+ * decide what to do with it. Passing NULL restores the normal output.
+ */
+void display_set_output(FILE *fp)
+{
+ display_out = fp;
+}
+
+void display_printf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(display_out ? display_out : stdout, fmt, ap);
+ va_end(ap);
+}
int default_pager_num_columns = FALLBACK_TERMINAL_WIDTH;
enum monitor_color setting_monitor_color = COLOR_AUTO;
diff --git a/monitor/display.h b/monitor/display.h
index 5f83a9a18273..93773e651ef1 100644
--- a/monitor/display.h
+++ b/monitor/display.h
@@ -12,9 +12,18 @@
#include <stdbool.h>
#include <inttypes.h>
#include <ctype.h>
+#include <stdio.h>
bool use_color(void);
+/*
+ * All decoding output goes through here so that it can be captured, for
+ * example to match a whole frame against a query before showing it.
+ */
+void display_printf(const char *fmt, ...)
+ __attribute__((format(printf, 1, 2)));
+void display_set_output(FILE *fp);
+
enum monitor_color { COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER };
void set_monitor_color(enum monitor_color);
@@ -44,7 +53,7 @@ void set_monitor_color(enum monitor_color);
#define print_indent(indent, color1, prefix, title, color2, fmt, args...) \
do { \
- printf("%*c%s%s%s%s" fmt "%s\n", (indent), ' ', \
+ display_printf("%*c%s%s%s%s" fmt "%s\n", (indent), ' ', \
use_color() ? (color1) : "", prefix, title, \
use_color() ? (color2) : "", ## args, \
use_color() ? COLOR_OFF : ""); \
diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index a132bcf397f4..716cb255013c 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
@@ -443,73 +443,73 @@ static char *mode2str(uint8_t mode)
static void l2cap_ctrl_ext_parse(struct l2cap_frame *frame, uint32_t ctrl)
{
- printf(" %s:",
+ display_printf(" %s:",
ctrl & L2CAP_EXT_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
if (ctrl & L2CAP_EXT_CTRL_FRAME_TYPE) {
- printf(" %s",
+ display_printf(" %s",
supervisory2str((ctrl & L2CAP_EXT_CTRL_SUPERVISE_MASK) >>
L2CAP_EXT_CTRL_SUPER_SHIFT));
if (ctrl & L2CAP_EXT_CTRL_POLL)
- printf(" P-bit");
+ display_printf(" P-bit");
} else {
uint8_t sar = (ctrl & L2CAP_EXT_CTRL_SAR_MASK) >>
L2CAP_EXT_CTRL_SAR_SHIFT;
- printf(" %s", sar2str(sar));
+ display_printf(" %s", sar2str(sar));
if (sar == L2CAP_SAR_START) {
uint16_t len;
if (!l2cap_frame_get_le16(frame, &len))
return;
- printf(" (len %d)", len);
+ display_printf(" (len %d)", len);
}
- printf(" TxSeq %d", (ctrl & L2CAP_EXT_CTRL_TXSEQ_MASK) >>
+ display_printf(" TxSeq %d", (ctrl & L2CAP_EXT_CTRL_TXSEQ_MASK) >>
L2CAP_EXT_CTRL_TXSEQ_SHIFT);
}
- printf(" ReqSeq %d", (ctrl & L2CAP_EXT_CTRL_REQSEQ_MASK) >>
+ display_printf(" ReqSeq %d", (ctrl & L2CAP_EXT_CTRL_REQSEQ_MASK) >>
L2CAP_EXT_CTRL_REQSEQ_SHIFT);
if (ctrl & L2CAP_EXT_CTRL_FINAL)
- printf(" F-bit");
+ display_printf(" F-bit");
}
static void l2cap_ctrl_parse(struct l2cap_frame *frame, uint32_t ctrl)
{
- printf(" %s:",
+ display_printf(" %s:",
ctrl & L2CAP_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
if (ctrl & 0x01) {
- printf(" %s",
+ display_printf(" %s",
supervisory2str((ctrl & L2CAP_CTRL_SUPERVISE_MASK) >>
L2CAP_CTRL_SUPER_SHIFT));
if (ctrl & L2CAP_CTRL_POLL)
- printf(" P-bit");
+ display_printf(" P-bit");
} else {
uint8_t sar;
sar = (ctrl & L2CAP_CTRL_SAR_MASK) >> L2CAP_CTRL_SAR_SHIFT;
- printf(" %s", sar2str(sar));
+ display_printf(" %s", sar2str(sar));
if (sar == L2CAP_SAR_START) {
uint16_t len;
if (!l2cap_frame_get_le16(frame, &len))
return;
- printf(" (len %d)", len);
+ display_printf(" (len %d)", len);
}
- printf(" TxSeq %d", (ctrl & L2CAP_CTRL_TXSEQ_MASK) >>
+ display_printf(" TxSeq %d", (ctrl & L2CAP_CTRL_TXSEQ_MASK) >>
L2CAP_CTRL_TXSEQ_SHIFT);
}
- printf(" ReqSeq %d", (ctrl & L2CAP_CTRL_REQSEQ_MASK) >>
+ display_printf(" ReqSeq %d", (ctrl & L2CAP_CTRL_REQSEQ_MASK) >>
L2CAP_CTRL_REQSEQ_SHIFT);
if (ctrl & L2CAP_CTRL_FINAL)
- printf(" F-bit");
+ display_printf(" F-bit");
}
#define MAX_INDEX 16
@@ -2732,7 +2732,7 @@ void l2cap_frame(uint16_t index, bool in, uint16_t handle, uint16_t cid,
l2cap_ctrl_parse(&frame, ctrl16);
}
- printf("\n");
+ display_printf("\n");
break;
}
diff --git a/monitor/lmp.c b/monitor/lmp.c
index d415699e4607..f58dde13de87 100644
--- a/monitor/lmp.c
+++ b/monitor/lmp.c
@@ -913,12 +913,12 @@ void lmp_todo(void)
{
int i;
- printf("LMP operations with missing decodings:\n");
+ display_printf("LMP operations with missing decodings:\n");
for (i = 0; lmp_table[i].str; i++) {
if (lmp_table[i].func)
continue;
- printf("\t%s\n", lmp_table[i].str);
+ display_printf("\t%s\n", lmp_table[i].str);
}
}
diff --git a/monitor/main.c b/monitor/main.c
index cc947af1ffc4..dc37294c5c27 100644
--- a/monitor/main.c
+++ b/monitor/main.c
@@ -44,10 +44,10 @@ static void signal_callback(int signum, void *user_data)
static void usage(void)
{
- printf("btmon - Bluetooth monitor\n"
+ display_printf("btmon - Bluetooth monitor\n"
"Usage:\n");
- printf("\tbtmon [options]\n");
- printf("options:\n"
+ display_printf("\tbtmon [options]\n");
+ display_printf("options:\n"
"\t-r, --read <file> Read traces in btsnoop format\n"
"\t-w, --write <file> Save traces in btsnoop format\n"
"\t-a, --analyze <file> Analyze traces in btsnoop format\n"
@@ -244,7 +244,7 @@ int main(int argc, char *argv[])
lmp_todo();
return EXIT_SUCCESS;
case 'v':
- printf("%s\n", VERSION);
+ display_printf("%s\n", VERSION);
return EXIT_SUCCESS;
case 'h':
usage();
@@ -264,7 +264,7 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
- printf("Bluetooth monitor ver %s\n", VERSION);
+ display_printf("Bluetooth monitor ver %s\n", VERSION);
keys_setup();
@@ -284,7 +284,7 @@ int main(int argc, char *argv[])
}
if (writer_path && !control_writer(writer_path)) {
- printf("Failed to open '%s'\n", writer_path);
+ display_printf("Failed to open '%s'\n", writer_path);
return EXIT_FAILURE;
}
diff --git a/monitor/packet.c b/monitor/packet.c
index 3ee53c2340a5..de3c6c5026da 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -709,7 +709,7 @@ void packet_select_index(uint16_t index)
index_filter = true;
}
-#define print_space(x) printf("%*c", (x), ' ');
+#define print_space(x) display_printf("%*c", (x), ' ');
void packet_set_fallback_manufacturer(uint16_t manufacturer)
{
@@ -919,12 +919,12 @@ static void print_packet(struct timeval *tv, struct ucred *cred, char ident,
}
if (ts_len > 0) {
- printf("%s", line);
+ display_printf("%s", line);
if (len < col)
print_space(col - len - ts_len - 1);
- printf("%s%s\n", use_color() ? COLOR_TIMESTAMP : "", ts_str);
+ display_printf("%s%s\n", use_color() ? COLOR_TIMESTAMP : "", ts_str);
} else
- printf("%s\n", line);
+ display_printf("%s\n", line);
}
static const struct {
@@ -18654,7 +18654,7 @@ void packet_todo(void)
{
int i;
- printf("HCI commands with missing decodings:\n");
+ display_printf("HCI commands with missing decodings:\n");
for (i = 0; opcode_table[i].str; i++) {
if (opcode_table[i].bit < 0)
@@ -18663,22 +18663,22 @@ void packet_todo(void)
if (opcode_table[i].cmd_func)
continue;
- printf("\t%s\n", opcode_table[i].str);
+ display_printf("\t%s\n", opcode_table[i].str);
}
- printf("HCI events with missing decodings:\n");
+ display_printf("HCI events with missing decodings:\n");
for (i = 0; event_table[i].str; i++) {
if (event_table[i].func)
continue;
- printf("\t%s\n", event_table[i].str);
+ display_printf("\t%s\n", event_table[i].str);
}
for (i = 0; le_meta_event_table[i].str; i++) {
if (le_meta_event_table[i].func)
continue;
- printf("\t%s\n", le_meta_event_table[i].str);
+ display_printf("\t%s\n", le_meta_event_table[i].str);
}
}
diff --git a/monitor/rfcomm.c b/monitor/rfcomm.c
index b03f44fe90c9..4199101275a2 100644
--- a/monitor/rfcomm.c
+++ b/monitor/rfcomm.c
@@ -139,15 +139,15 @@ static inline bool mcc_test(struct rfcomm_frame *rfcomm_frame, uint8_t indent)
struct l2cap_frame *frame = &rfcomm_frame->l2cap_frame;
uint8_t data;
- printf("%*cTest Data: 0x ", indent, ' ');
+ display_printf("%*cTest Data: 0x ", indent, ' ');
while (frame->size > 1) {
if (!l2cap_frame_get_u8(frame, &data))
return false;
- printf("%2.2x ", data);
+ display_printf("%2.2x ", data);
}
- printf("\n");
+ display_printf("\n");
return true;
}
diff --git a/tools/l2test.c b/tools/l2test.c
index 08d2269936b9..2e2606db13b9 100644
--- a/tools/l2test.c
+++ b/tools/l2test.c
@@ -16,6 +16,7 @@
#define _GNU_SOURCE
#include <stdio.h>
+#include <stdarg.h>
#include <stdbool.h>
#include <errno.h>
#include <ctype.h>
@@ -334,6 +335,15 @@ bool use_color(void)
return false;
}
+void display_printf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
static const struct bitfield_data phy_table[] = {
{ 0, "BR1M1SLOT" },
{ 1, "BR1M3SLOT" },
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v1 2/6] monitor: Separate the frames for a pager reading records
2026-09-17 20:45 [PATCH BlueZ v1 0/6] monitor: Search the frames with a pager Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 1/6] monitor: Route the decoding output through a single function Luiz Augusto von Dentz
@ 2026-09-17 20:45 ` Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 3/6] monitor: Hand the captured frames to the pager on Ctrl-R Luiz Augusto von Dentz
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-17 20:45 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
A frame spans several lines, so a pager that works on records rather than
lines has no way of telling where one ends. Feeding a trace to fzf with
--read0 makes the whole of it a single entry, and without --read0 each
line becomes an entry of its own, so searching finds the line reporting
an error without the header saying which controller, handle and time it
belongs to.
Separate the frames with a NUL when the pager is going to read records,
which is asked for either by --print0 or by --read0 already being in
PAGER:
$ PAGER='fzf --read0' btmon -r hcidump.log
$ btmon -r hcidump.log --print0 | fzf --read0
Nothing is separated unless it was asked for, so the output is unchanged
for a pager reading lines, which would otherwise show the separator as a
stray character between the frames.
The model wrote this, which the author reviewed and verified by counting
the separators against the frames, by checking that a pager reading lines
still receives none, and that the output is unchanged when neither is
asked for.
Assisted-by: opencode:claude-opus-5
---
Makefile.tools | 1 +
monitor/control.c | 15 ++++++
monitor/find.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++
monitor/find.h | 19 +++++++
monitor/main.c | 15 +++++-
5 files changed, 177 insertions(+), 1 deletion(-)
create mode 100644 monitor/find.c
create mode 100644 monitor/find.h
diff --git a/Makefile.tools b/Makefile.tools
index 6844a52ac739..671b40fb0e42 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -58,6 +58,7 @@ monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
monitor/jlink.h monitor/jlink.c \
monitor/tty.h monitor/emulator.h \
monitor/att.h monitor/att.c \
+ monitor/find.h monitor/find.c \
src/log.h src/log.c \
src/textfile.h src/textfile.c \
src/settings.h src/settings.c
diff --git a/monitor/control.c b/monitor/control.c
index 8ed221e08a02..4be6a4687005 100644
--- a/monitor/control.c
+++ b/monitor/control.c
@@ -39,6 +39,7 @@
#include "src/shared/mainloop.h"
#include "display.h"
+#include "find.h"
#include "packet.h"
#include "hcidump.h"
#include "ellisys.h"
@@ -962,8 +963,10 @@ static void data_callback(int fd, uint32_t events, void *user_data)
switch (data->channel) {
case HCI_CHANNEL_CONTROL:
+ find_frame_begin();
packet_control(tv, cred, index, opcode,
data->buf, pktlen);
+ find_frame_end();
break;
case HCI_CHANNEL_MONITOR:
if (pktlen > (len - MGMT_HDR_SIZE))
@@ -973,8 +976,10 @@ static void data_callback(int fd, uint32_t events, void *user_data)
data->buf, pktlen);
ellisys_inject_hci(tv, index, opcode,
data->buf, pktlen);
+ find_frame_begin();
packet_monitor(tv, cred, index, opcode,
data->buf, pktlen);
+ find_frame_end();
break;
}
}
@@ -1120,8 +1125,10 @@ static void kmsg_callback(int fd, uint32_t events, void *user_data)
btsnoop_write_hci(btsnoop_file, &tv, HCI_DEV_NONE,
BTSNOOP_OPCODE_SYSTEM_NOTE, 0, msg, len);
+ find_frame_begin();
packet_monitor(&tv, NULL, HCI_DEV_NONE,
BTSNOOP_OPCODE_SYSTEM_NOTE, msg, len);
+ find_frame_end();
}
static int open_kmsg(void)
@@ -1168,8 +1175,10 @@ static void client_callback(int fd, uint32_t events, void *user_data)
opcode = le16_to_cpu(hdr->opcode);
index = le16_to_cpu(hdr->index);
+ find_frame_begin();
packet_monitor(NULL, NULL, index, opcode,
data->buf + MGMT_HDR_SIZE, pktlen);
+ find_frame_end();
data->offset -= pktlen + MGMT_HDR_SIZE;
@@ -1386,8 +1395,10 @@ static void process_data(struct control_data *data)
hdr->ext_hdr + hdr->hdr_len, pktlen);
ellisys_inject_hci(tv, 0, opcode, hdr->ext_hdr + hdr->hdr_len,
pktlen);
+ find_frame_begin();
packet_monitor(tv, NULL, 0, opcode,
hdr->ext_hdr + hdr->hdr_len, pktlen);
+ find_frame_end();
data->offset -= 2 + data_len;
@@ -1573,7 +1584,9 @@ void control_reader(const char *path, bool pager)
if (opcode == 0xffff)
continue;
+ find_frame_begin();
packet_monitor(&tv, NULL, index, opcode, buf, pktlen);
+ find_frame_end();
ellisys_inject_hci(&tv, index, opcode, buf, pktlen);
}
break;
@@ -1586,7 +1599,9 @@ void control_reader(const char *path, bool pager)
buf, &pktlen))
break;
+ find_frame_begin();
packet_simulator(&tv, frequency, buf, pktlen);
+ find_frame_end();
}
break;
}
diff --git a/monitor/find.c b/monitor/find.c
new file mode 100644
index 000000000000..649d722ee197
--- /dev/null
+++ b/monitor/find.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2026 Intel Corporation
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "monitor/display.h"
+#include "monitor/find.h"
+
+static bool enabled;
+static bool records; /* Separate the frames with a NUL */
+static bool printed; /* Something has been written out already */
+static bool print0;
+
+static char *capture_buf;
+static size_t capture_len;
+static FILE *capture;
+
+void find_set_print0(void)
+{
+ print0 = true;
+}
+
+/*
+ * A frame spans several lines, so a pager that works on records rather
+ * than lines has to be told where one ends. The request is already in
+ * PAGER, so take it from there as well as from the command line.
+ */
+static bool want_records(void)
+{
+ const char *pager;
+
+ if (print0)
+ return true;
+
+ pager = getenv("PAGER");
+
+ return pager && strstr(pager, "--read0");
+}
+
+void find_setup(void)
+{
+ records = want_records();
+
+ /*
+ * Nothing is kept, but the output still has to be seen to know
+ * where one frame ends and the next begins.
+ */
+ if (records)
+ enabled = true;
+}
+
+void find_frame_begin(void)
+{
+ if (!enabled)
+ return;
+
+ capture_buf = NULL;
+ capture_len = 0;
+
+ capture = open_memstream(&capture_buf, &capture_len);
+ if (!capture)
+ return;
+
+ display_set_output(capture);
+}
+
+void find_frame_end(void)
+{
+ if (!enabled || !capture)
+ return;
+
+ display_set_output(NULL);
+ fclose(capture);
+ capture = NULL;
+
+ /* A frame that was filtered out produces no output */
+ if (!capture_len) {
+ free(capture_buf);
+ capture_buf = NULL;
+ return;
+ }
+
+ if (records) {
+ const char nul = '\0';
+ size_t len = capture_len;
+
+ /*
+ * The newline ending the frame is what separates the lines
+ * within it, so leave it out of a record or it shows as a
+ * blank line at the end of the entry.
+ */
+ if (len && capture_buf[len - 1] == '\n')
+ len--;
+
+ if (printed)
+ fwrite(&nul, 1, 1, stdout);
+
+ fwrite(capture_buf, 1, len, stdout);
+ } else {
+ fwrite(capture_buf, 1, capture_len, stdout);
+ }
+
+ fflush(stdout);
+ printed = true;
+
+ free(capture_buf);
+ capture_buf = NULL;
+}
+
+void find_cleanup(void)
+{
+ enabled = false;
+}
diff --git a/monitor/find.h b/monitor/find.h
new file mode 100644
index 000000000000..c6b2036ba3a6
--- /dev/null
+++ b/monitor/find.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2026 Intel Corporation
+ *
+ *
+ */
+
+#include <stdbool.h>
+
+void find_set_print0(void);
+void find_setup(void);
+
+void find_frame_begin(void);
+void find_frame_end(void);
+
+void find_cleanup(void);
diff --git a/monitor/main.c b/monitor/main.c
index dc37294c5c27..ce7bae7f5cae 100644
--- a/monitor/main.c
+++ b/monitor/main.c
@@ -31,6 +31,7 @@
#include "ellisys.h"
#include "control.h"
#include "display.h"
+#include "find.h"
static void signal_callback(int signum, void *user_data)
{
@@ -69,6 +70,8 @@ static void usage(void)
"\t-I, --iso Dump ISO traffic\n"
"\t-E, --ellisys [ip] Send Ellisys HCI Injection\n"
"\t-P, --no-pager Disable pager usage\n"
+ "\t-0, --print0 Separate frames with a NUL, for a\n"
+ "\t pager reading records\n"
"\t-J --jlink <device>,[<serialno>],[<interface>],[<speed>]\n"
"\t Read data from RTT\n"
"\t-R --rtt [<address>],[<area>],[<name>]\n"
@@ -98,6 +101,7 @@ static const struct option main_options[] = {
{ "iso", no_argument, NULL, 'I' },
{ "ellisys", required_argument, NULL, 'E' },
{ "no-pager", no_argument, NULL, 'P' },
+ { "print0", no_argument, NULL, '0' },
{ "jlink", required_argument, NULL, 'J' },
{ "rtt", required_argument, NULL, 'R' },
{ "columns", required_argument, NULL, 'C' },
@@ -133,7 +137,7 @@ int main(int argc, char *argv[])
struct sockaddr_un addr;
opt = getopt_long(argc, argv,
- "r:w:a:s:p:i:d:B:V:MKNtTSAIE:PJ:R:C:c:vh",
+ "r:w:a:s:p:i:d:B:V:MKNtTSAIE:P0J:R:C:c:vh",
main_options, NULL);
if (opt < 0)
break;
@@ -217,6 +221,9 @@ int main(int argc, char *argv[])
case 'P':
use_pager = false;
break;
+ case '0':
+ find_set_print0();
+ break;
case 'J':
jlink = optarg;
break;
@@ -279,6 +286,8 @@ int main(int argc, char *argv[])
if (ellisys_server)
ellisys_enable(ellisys_server, ellisys_port);
+ find_setup();
+
control_reader(reader_path, use_pager);
return EXIT_SUCCESS;
}
@@ -300,8 +309,12 @@ int main(int argc, char *argv[])
if (jlink && control_rtt(jlink, rtt) < 0)
return EXIT_FAILURE;
+ find_setup();
+
exit_status = mainloop_run_with_signal(signal_callback, NULL);
+ find_cleanup();
+
keys_cleanup();
return exit_status;
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v1 3/6] monitor: Hand the captured frames to the pager on Ctrl-R
2026-09-17 20:45 [PATCH BlueZ v1 0/6] monitor: Search the frames with a pager Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 1/6] monitor: Route the decoding output through a single function Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 2/6] monitor: Separate the frames for a pager reading records Luiz Augusto von Dentz
@ 2026-09-17 20:45 ` Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 4/6] doc/btmon: Document searching the frames Luiz Augusto von Dentz
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-17 20:45 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Looking for something in a running capture means stopping it and reading
back the log, losing whatever would have arrived meanwhile, or scrolling
the terminal by hand while the trace keeps moving.
Collect the frames as they are printed and hand them to the pager on
Ctrl-R, in the manner of the shell. The capture keeps running underneath,
and closing the pager returns to it, printing whatever arrived while it
was up so that the trace on the terminal has no gap.
The capture is never paused for this. Anything not read in time is
dropped by the kernel, so the pager runs on its own and is only checked
for having closed, rather than being waited for.
The frames are handed over as a file rather than through a pipe, so that
filling it cannot block the monitor and cost the capture any packets,
separated as they are elsewhere when the pager is going to read records.
Frames are only collected when the output is a terminal, so a capture
that is piped or redirected behaves exactly as it always has. The
terminal is switched to reading keys as they are typed, but signals are
left enabled so that Ctrl-C still interrupts the capture as before.
A capture runs for as long as it is left running, so the frames are held
in a ring and the oldest are dropped once it is full.
The model wrote this, which the author reviewed and verified against a
capture fed through a terminal, covering the printing before and after,
the capture continuing to be collected while the pager was up, the
frames arriving then being printed on close, and a piped capture being
left alone.
Assisted-by: opencode:claude-opus-5
---
monitor/find.c | 485 ++++++++++++++++++++++++++++++++++++++++++-------
monitor/find.h | 2 +-
monitor/main.c | 5 +-
3 files changed, 428 insertions(+), 64 deletions(-)
diff --git a/monitor/find.c b/monitor/find.c
index 649d722ee197..32600964faf1 100644
--- a/monitor/find.c
+++ b/monitor/find.c
@@ -17,19 +17,399 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
+#include <termios.h>
+#include <signal.h>
+#include <sys/epoll.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+#include "src/shared/mainloop.h"
#include "monitor/display.h"
#include "monitor/find.h"
+/*
+ * A capture runs for as long as it is left running, so the oldest frames
+ * are dropped once this many are held rather than letting the monitor be
+ * killed for using too much memory.
+ */
+#define FIND_MAX_FRAMES 200000
+
+/* How often the pager is checked for having been closed */
+#define FIND_POLL_MSEC 100
+
+struct find_frame {
+ char *text;
+ size_t len;
+ uint64_t seq;
+};
+
+/*
+ * The frames are held in a ring, so that the oldest can be dropped once it
+ * is full without having to move the rest.
+ */
+static struct find_frame *frames;
+static unsigned int num_frames; /* Held right now */
+static unsigned int max_frames; /* Allocated */
+static unsigned int first_frame; /* Oldest, within the ring */
+static uint64_t next_seq;
+
static bool enabled;
+static bool store; /* Keep the frames for handing to the pager */
static bool records; /* Separate the frames with a NUL */
static bool printed; /* Something has been written out already */
static bool print0;
+static bool raw_mode;
+static int poll_id = -1;
+static struct termios saved_term;
+
+static pid_t pager_pid;
+static int saved_stdout = -1;
+static uint64_t pager_seq; /* Frames from here are yet to be printed */
static char *capture_buf;
static size_t capture_len;
static FILE *capture;
+static struct find_frame *frame_at(unsigned int n)
+{
+ return &frames[(first_frame + n) % max_frames];
+}
+
+static void frame_free(struct find_frame *frame)
+{
+ free(frame->text);
+ memset(frame, 0, sizeof(*frame));
+}
+
+/* Make room for one more frame, dropping the oldest once the ring is full */
+static struct find_frame *frame_next(void)
+{
+ struct find_frame *frame;
+
+ if (num_frames == FIND_MAX_FRAMES) {
+ frame = &frames[first_frame];
+ frame_free(frame);
+ first_frame = (first_frame + 1) % max_frames;
+ return frame;
+ }
+
+ if (num_frames == max_frames) {
+ unsigned int size = max_frames ? max_frames * 2 : 1024;
+ void *tmp;
+
+ if (size > FIND_MAX_FRAMES)
+ size = FIND_MAX_FRAMES;
+
+ tmp = realloc(frames, size * sizeof(*frames));
+ if (!tmp)
+ return NULL;
+
+ frames = tmp;
+ max_frames = size;
+ }
+
+ frame = &frames[(first_frame + num_frames) % max_frames];
+ num_frames++;
+
+ return frame;
+}
+
+void find_frame_begin(void)
+{
+ if (!enabled)
+ return;
+
+ capture_buf = NULL;
+ capture_len = 0;
+
+ capture = open_memstream(&capture_buf, &capture_len);
+ if (!capture)
+ return;
+
+ display_set_output(capture);
+}
+
+void find_frame_end(void)
+{
+ struct find_frame *frame;
+
+ if (!enabled || !capture)
+ return;
+
+ display_set_output(NULL);
+ fclose(capture);
+ capture = NULL;
+
+ /* A frame that was filtered out produces no output */
+ if (!capture_len) {
+ free(capture_buf);
+ capture_buf = NULL;
+ return;
+ }
+
+ /*
+ * Keep the trace on the terminal while the pager is not up. What
+ * arrives while it is up is printed once it closes, so that the
+ * trace on the terminal has no gap.
+ */
+ if (!pager_pid) {
+ const char nul = '\0';
+ size_t len = capture_len;
+
+ /*
+ * Only what is read as records is written as records. While
+ * capturing this is the trace on the terminal, which keeps
+ * its newlines or the next frame carries on the same line.
+ * The pager is given its own copy.
+ */
+ if (records && !store) {
+ /*
+ * The newline ending the frame is what separates
+ * the lines within it, so leave it out of a record
+ * or it shows as a blank line at the end of the
+ * entry.
+ */
+ if (len && capture_buf[len - 1] == '\n')
+ len--;
+
+ if (printed)
+ fwrite(&nul, 1, 1, stdout);
+ }
+
+ fwrite(capture_buf, 1, len, stdout);
+ fflush(stdout);
+ printed = true;
+ }
+
+ if (!store) {
+ free(capture_buf);
+ capture_buf = NULL;
+ return;
+ }
+
+ frame = frame_next();
+ if (!frame) {
+ free(capture_buf);
+ capture_buf = NULL;
+ return;
+ }
+
+ frame->text = capture_buf;
+ frame->len = capture_len;
+ frame->seq = next_seq++;
+ capture_buf = NULL;
+}
+
+/*
+ * Read the keys as they are typed rather than a line at a time. Signals are
+ * left enabled so that Ctrl-C still interrupts the capture as it always has.
+ */
+static void term_raw(void)
+{
+ struct termios term;
+
+ if (raw_mode)
+ return;
+
+ if (tcgetattr(STDIN_FILENO, &saved_term) < 0)
+ return;
+
+ term = saved_term;
+ term.c_lflag &= ~(ICANON | ECHO);
+ term.c_cc[VMIN] = 1;
+ term.c_cc[VTIME] = 0;
+
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0)
+ return;
+
+ raw_mode = true;
+}
+
+static void term_restore(void)
+{
+ if (!raw_mode)
+ return;
+
+ tcsetattr(STDIN_FILENO, TCSANOW, &saved_term);
+ raw_mode = false;
+}
+
+/*
+ * Hand the frames over as a file rather than through a pipe, so that
+ * filling it cannot block the monitor and cost the capture any packets.
+ * They are separated by a NUL so that a pager able to take records, such
+ * as fzf with --read0, sees a whole frame as one entry instead of matching
+ * the individual lines within it.
+ */
+static int frames_to_file(void)
+{
+ unsigned int i;
+ int fd;
+
+ fd = memfd_create("btmon-frames", MFD_CLOEXEC);
+ if (fd < 0)
+ return -1;
+
+ for (i = 0; i < num_frames; i++) {
+ const struct find_frame *frame = frame_at(i);
+ const char nul = '\0';
+ size_t len = frame->len;
+
+ if (records) {
+ if (i && write(fd, &nul, 1) < 0)
+ break;
+
+ /* Leave out the newline ending the frame */
+ if (len && frame->text[len - 1] == '\n')
+ len--;
+ }
+
+ if (write(fd, frame->text, len) < 0)
+ break;
+ }
+
+ if (lseek(fd, 0, SEEK_SET) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static void pager_close(void)
+{
+ unsigned int i;
+
+ if (!pager_pid)
+ return;
+
+ pager_pid = 0;
+
+ /* Put the monitor back in charge of the terminal */
+ if (saved_stdout >= 0) {
+ dup2(saved_stdout, STDOUT_FILENO);
+ close(saved_stdout);
+ saved_stdout = -1;
+ }
+
+ term_raw();
+
+ /* Print whatever arrived while the pager was up */
+ for (i = 0; i < num_frames; i++) {
+ const struct find_frame *frame = frame_at(i);
+
+ if (frame->seq >= pager_seq)
+ fwrite(frame->text, 1, frame->len, stdout);
+ }
+
+ fflush(stdout);
+}
+
+static void pager_open(void)
+{
+ const char *pager;
+ int fd;
+
+ if (pager_pid || !num_frames)
+ return;
+
+ fd = frames_to_file();
+ if (fd < 0)
+ return;
+
+ pager = getenv("PAGER");
+ if (pager && (!*pager || !strcmp(pager, "cat")))
+ pager = NULL;
+
+ fflush(stdout);
+
+ /* The pager reads the terminal from here on */
+ term_restore();
+ mainloop_remove_fd(STDIN_FILENO);
+
+ saved_stdout = dup(STDOUT_FILENO);
+
+ pager_pid = fork();
+ if (pager_pid < 0) {
+ pager_pid = 0;
+ close(fd);
+ close(saved_stdout);
+ saved_stdout = -1;
+ term_raw();
+ return;
+ }
+
+ if (!pager_pid) {
+ dup2(fd, STDIN_FILENO);
+ close(fd);
+
+ if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
+ _exit(EXIT_FAILURE);
+
+ if (pager) {
+ execlp(pager, pager, NULL);
+ execl("/bin/sh", "sh", "-c", pager, NULL);
+ }
+
+ execlp("pager", "pager", NULL);
+ execlp("less", "less", NULL);
+ execlp("more", "more", NULL);
+
+ _exit(EXIT_FAILURE);
+ }
+
+ close(fd);
+
+ pager_seq = next_seq;
+}
+
+static void key_callback(int fd, uint32_t events, void *user_data)
+{
+ char buf[32];
+ ssize_t len, i;
+
+ if (events & (EPOLLERR | EPOLLHUP)) {
+ mainloop_quit();
+ return;
+ }
+
+ len = read(STDIN_FILENO, buf, sizeof(buf));
+ if (len <= 0)
+ return;
+
+ /*
+ * Anything else typed at a running capture is left alone, so that
+ * the terminal behaves as it did before.
+ */
+ for (i = 0; i < len; i++) {
+ if (buf[i] == 0x12) { /* Ctrl-R */
+ pager_open();
+ return;
+ }
+ }
+}
+
+static void arm_keys(void)
+{
+ mainloop_add_fd(STDIN_FILENO, EPOLLIN, key_callback, NULL, NULL);
+}
+
+/*
+ * The pager runs on its own so that the monitor keeps draining the socket
+ * while it is up, as anything not read in time is dropped by the kernel.
+ */
+static void poll_callback(int id, void *user_data)
+{
+ if (pager_pid && waitpid(pager_pid, NULL, WNOHANG) == pager_pid) {
+ pager_close();
+ arm_keys();
+ }
+
+ mainloop_modify_timeout(id, FIND_POLL_MSEC);
+}
+
void find_set_print0(void)
{
print0 = true;
@@ -52,77 +432,60 @@ static bool want_records(void)
return pager && strstr(pager, "--read0");
}
-void find_setup(void)
+void find_setup(bool live)
{
records = want_records();
+ if (live && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
+ enabled = true;
+ store = true;
+
+ term_raw();
+ arm_keys();
+
+ poll_id = mainloop_add_timeout(FIND_POLL_MSEC, poll_callback,
+ NULL, NULL);
+ return;
+ }
+
/*
- * Nothing is kept, but the output still has to be seen to know
- * where one frame ends and the next begins.
+ * Nothing is kept when only the separators are wanted, but the
+ * output still has to be seen to know where a frame ends.
*/
if (records)
enabled = true;
}
-void find_frame_begin(void)
-{
- if (!enabled)
- return;
-
- capture_buf = NULL;
- capture_len = 0;
-
- capture = open_memstream(&capture_buf, &capture_len);
- if (!capture)
- return;
-
- display_set_output(capture);
-}
-
-void find_frame_end(void)
-{
- if (!enabled || !capture)
- return;
-
- display_set_output(NULL);
- fclose(capture);
- capture = NULL;
-
- /* A frame that was filtered out produces no output */
- if (!capture_len) {
- free(capture_buf);
- capture_buf = NULL;
- return;
- }
-
- if (records) {
- const char nul = '\0';
- size_t len = capture_len;
-
- /*
- * The newline ending the frame is what separates the lines
- * within it, so leave it out of a record or it shows as a
- * blank line at the end of the entry.
- */
- if (len && capture_buf[len - 1] == '\n')
- len--;
-
- if (printed)
- fwrite(&nul, 1, 1, stdout);
-
- fwrite(capture_buf, 1, len, stdout);
- } else {
- fwrite(capture_buf, 1, capture_len, stdout);
- }
-
- fflush(stdout);
- printed = true;
-
- free(capture_buf);
- capture_buf = NULL;
-}
-
void find_cleanup(void)
{
+ unsigned int i;
+
+ if (pager_pid) {
+ kill(pager_pid, SIGTERM);
+ waitpid(pager_pid, NULL, 0);
+ pager_pid = 0;
+ }
+
+ if (saved_stdout >= 0) {
+ dup2(saved_stdout, STDOUT_FILENO);
+ close(saved_stdout);
+ saved_stdout = -1;
+ }
+
+ term_restore();
+
+ if (poll_id >= 0) {
+ mainloop_remove_timeout(poll_id);
+ poll_id = -1;
+ }
+
+ for (i = 0; i < num_frames; i++)
+ frame_free(frame_at(i));
+
+ free(frames);
+ frames = NULL;
+ num_frames = 0;
+ max_frames = 0;
+ first_frame = 0;
enabled = false;
}
diff --git a/monitor/find.h b/monitor/find.h
index c6b2036ba3a6..3048ab69e4c9 100644
--- a/monitor/find.h
+++ b/monitor/find.h
@@ -11,7 +11,7 @@
#include <stdbool.h>
void find_set_print0(void);
-void find_setup(void);
+void find_setup(bool live);
void find_frame_begin(void);
void find_frame_end(void);
diff --git a/monitor/main.c b/monitor/main.c
index ce7bae7f5cae..25de945446a9 100644
--- a/monitor/main.c
+++ b/monitor/main.c
@@ -286,7 +286,7 @@ int main(int argc, char *argv[])
if (ellisys_server)
ellisys_enable(ellisys_server, ellisys_port);
- find_setup();
+ find_setup(false);
control_reader(reader_path, use_pager);
return EXIT_SUCCESS;
@@ -309,7 +309,8 @@ int main(int argc, char *argv[])
if (jlink && control_rtt(jlink, rtt) < 0)
return EXIT_FAILURE;
- find_setup();
+ /* Watch for the key that brings the pager up */
+ find_setup(true);
exit_status = mainloop_run_with_signal(signal_callback, NULL);
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v1 4/6] doc/btmon: Document searching the frames
2026-09-17 20:45 [PATCH BlueZ v1 0/6] monitor: Search the frames with a pager Luiz Augusto von Dentz
` (2 preceding siblings ...)
2026-09-17 20:45 ` [PATCH BlueZ v1 3/6] monitor: Hand the captured frames to the pager on Ctrl-R Luiz Augusto von Dentz
@ 2026-09-17 20:45 ` Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 5/6] monitor: Prefer fzf as the pager when one is not set Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 6/6] doc/btmon: Document the pager choice Luiz Augusto von Dentz
5 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-17 20:45 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Describe how the frames are separated for a pager reading records, how the
ones seen so far are handed to the pager while capturing, and that they
are only collected when the output is a terminal.
The model drafted the text, which the author reviewed against the actual
behaviour.
Assisted-by: opencode:claude-opus-5
---
doc/btmon.rst | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/doc/btmon.rst b/doc/btmon.rst
index a08a6afa43f4..163289bd1ef0 100644
--- a/doc/btmon.rst
+++ b/doc/btmon.rst
@@ -96,6 +96,9 @@ OPTIONS
-E IP, --ellisys IP Send Ellisys HCI Injection.
-P, --no-pager Disable pager usage while reading the log file.
+-0, --print0 Separate the frames with a NUL, so that a pager
+ or a tool reading records rather than lines sees
+ a whole frame as one entry.
-J OPTIONS, --jlink OPTIONS Read data from RTT. Each options are comma(,)
separated without spaces.
@@ -616,6 +619,56 @@ The kernel forwarded this as a MGMT Device Connected event. bluetoothd
logged its ``connected_callback()``. Then data exchange began -- an L2CAP
parameter update and ATT MTU negotiation over the new ACL connection.
+SEARCHING THE FRAMES
+====================
+
+A frame spans several lines, so a pager that works on records rather than
+lines has to be told where one ends. Asking for that with ``--print0``, or
+by having ``--read0`` in ``PAGER``, separates the frames with a NUL so that
+a whole frame is one entry::
+
+ $ PAGER='fzf --read0' btmon -r hcidump.log
+ $ btmon -r hcidump.log --print0 | fzf --read0
+
+Without it each line becomes an entry of its own, so searching finds the
+line reporting an error without the header saying which controller, handle
+and time it belongs to.
+
+The newline that ends a frame is left out of a record, since it is what
+separates the lines within one and would otherwise show as a blank line at
+the end of every entry.
+
+Nothing is separated unless it was asked for, so a pager reading lines,
+such as ``less``, is unaffected and never shows the separator.
+
+Searching a running capture
+---------------------------
+
+While capturing, the frames seen so far can be handed to a pager at any
+time by pressing ``Ctrl-R``, in the manner of the shell. The capture keeps
+running underneath, and closing the pager returns to it.
+
+.. code-block::
+
+ $ btmon # then press Ctrl-R
+ $ PAGER='fzf --read0' btmon # then press Ctrl-R
+
+Whatever arrives while the pager is up is printed once it closes, so the
+trace on the terminal has no gap. The capture is never paused, as anything
+not read in time would be dropped by the kernel.
+
+The pager is taken from ``PAGER``, falling back to ``less``. Setting it to
+``cat`` or leaving it empty disables the pager, as elsewhere.
+
+Frames are only collected when the output is a terminal, so a capture that
+is piped or redirected behaves exactly as it always has. The terminal is
+switched to reading keys as they are typed, but signals are left enabled so
+``Ctrl-C`` still interrupts the capture.
+
+They are held in memory and the oldest are dropped once 200000 are held, so
+that a capture left running does not risk the monitor being killed for
+using too much memory.
+
ANALYZE MODE
============
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v1 5/6] monitor: Prefer fzf as the pager when one is not set
2026-09-17 20:45 [PATCH BlueZ v1 0/6] monitor: Search the frames with a pager Luiz Augusto von Dentz
` (3 preceding siblings ...)
2026-09-17 20:45 ` [PATCH BlueZ v1 4/6] doc/btmon: Document searching the frames Luiz Augusto von Dentz
@ 2026-09-17 20:45 ` Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 6/6] doc/btmon: Document the pager choice Luiz Augusto von Dentz
5 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-17 20:45 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
A trace is a poor fit for a plain pager. Every frame spans several lines
and what identifies one is spread between its header and its contents, so
finding something means paging through by hand.
Use fzf when PAGER is not set and it is installed, asking it for whole
frames and for the colours to be rendered rather than shown as escape
sequences:
fzf --ansi --read0
PAGER is still honoured when set, and setting it to cat or leaving it
empty still turns the pager off. The choice is shared with the frames
seen so far being handed over while capturing, so both arrive at the same
pager.
Frames are separated only when a pager that reads records is going to
read them, so redirected output and a pager that reads lines are both
left exactly as they were.
The model wrote this, which the author reviewed and verified by checking
which pager is started for each setting of PAGER, that the colours are
rendered rather than shown, and that redirected output is unchanged.
Assisted-by: opencode:claude-opus-5
---
monitor/display.c | 73 +++++++++++++++++++++++++++++++++++++++++++----
monitor/display.h | 3 ++
monitor/find.c | 20 +++++++++----
monitor/find.h | 2 +-
monitor/main.c | 4 +--
5 files changed, 88 insertions(+), 14 deletions(-)
diff --git a/monitor/display.c b/monitor/display.c
index b540155319a0..8d767e77e464 100644
--- a/monitor/display.c
+++ b/monitor/display.c
@@ -20,6 +20,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/prctl.h>
@@ -117,6 +118,69 @@ static void wait_for_terminate(pid_t pid)
}
}
+/* Look for a command in PATH, so that it can be preferred if present */
+static bool have_command(const char *name)
+{
+ const char *path = getenv("PATH");
+ char *dirs, *dir, *save = NULL;
+ bool found = false;
+
+ if (!path)
+ return false;
+
+ dirs = strdup(path);
+ if (!dirs)
+ return false;
+
+ for (dir = strtok_r(dirs, ":", &save); dir;
+ dir = strtok_r(NULL, ":", &save)) {
+ char file[PATH_MAX];
+
+ if (snprintf(file, sizeof(file), "%s/%s", dir, name) < 0)
+ continue;
+
+ if (!access(file, X_OK)) {
+ found = true;
+ break;
+ }
+ }
+
+ free(dirs);
+
+ return found;
+}
+
+bool pager_disabled(void)
+{
+ const char *pager = getenv("PAGER");
+
+ return pager && (!*pager || !strcmp(pager, "cat"));
+}
+
+/*
+ * A fuzzy finder is a far better fit for a trace than a plain pager, so
+ * prefer it when one is installed and nothing was asked for. Wherever it
+ * is used it is told to take whole frames rather than lines, and to
+ * render the colours instead of showing the escape sequences.
+ */
+const char *pager_command(void)
+{
+ static char cmd[256];
+ const char *pager = getenv("PAGER");
+
+ if (!pager || !*pager)
+ return have_command("fzf") ? "fzf --ansi --read0" : NULL;
+
+ if (!strstr(pager, "fzf"))
+ return pager;
+
+ snprintf(cmd, sizeof(cmd), "%s%s%s", pager,
+ strstr(pager, "--ansi") ? "" : " --ansi",
+ strstr(pager, "--read0") ? "" : " --read0");
+
+ return cmd;
+}
+
void open_pager(void)
{
const char *pager;
@@ -126,11 +190,10 @@ void open_pager(void)
if (pager_pid > 0)
return;
- pager = getenv("PAGER");
- if (pager) {
- if (!*pager || strcmp(pager, "cat") == 0)
- return;
- }
+ if (pager_disabled())
+ return;
+
+ pager = pager_command();
if (!(isatty(STDOUT_FILENO) > 0))
return;
diff --git a/monitor/display.h b/monitor/display.h
index 93773e651ef1..cad182f77c94 100644
--- a/monitor/display.h
+++ b/monitor/display.h
@@ -135,5 +135,8 @@ static inline void print_hex_field(const char *label, const uint8_t *data,
void set_default_pager_num_columns(int num_columns);
int num_columns(void);
+bool pager_disabled(void);
+const char *pager_command(void);
+
void open_pager(void);
void close_pager(void);
diff --git a/monitor/find.c b/monitor/find.c
index 32600964faf1..58c4f51d8bfb 100644
--- a/monitor/find.c
+++ b/monitor/find.c
@@ -60,6 +60,7 @@ static bool store; /* Keep the frames for handing to the pager */
static bool records; /* Separate the frames with a NUL */
static bool printed; /* Something has been written out already */
static bool print0;
+static bool use_pager;
static bool raw_mode;
static int poll_id = -1;
static struct termios saved_term;
@@ -312,16 +313,14 @@ static void pager_open(void)
const char *pager;
int fd;
- if (pager_pid || !num_frames)
+ if (pager_pid || !num_frames || !use_pager || pager_disabled())
return;
fd = frames_to_file();
if (fd < 0)
return;
- pager = getenv("PAGER");
- if (pager && (!*pager || !strcmp(pager, "cat")))
- pager = NULL;
+ pager = pager_command();
fflush(stdout);
@@ -427,13 +426,22 @@ static bool want_records(void)
if (print0)
return true;
- pager = getenv("PAGER");
+ /*
+ * Only separate the frames if something is actually going to read
+ * them as records. Nothing does when the output is redirected or
+ * the pager has been turned off.
+ */
+ if (!use_pager || pager_disabled() || !isatty(STDOUT_FILENO))
+ return false;
+
+ pager = pager_command();
return pager && strstr(pager, "--read0");
}
-void find_setup(bool live)
+void find_setup(bool live, bool pager)
{
+ use_pager = pager;
records = want_records();
if (live && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
diff --git a/monitor/find.h b/monitor/find.h
index 3048ab69e4c9..e7dad7aaf25c 100644
--- a/monitor/find.h
+++ b/monitor/find.h
@@ -11,7 +11,7 @@
#include <stdbool.h>
void find_set_print0(void);
-void find_setup(bool live);
+void find_setup(bool live, bool pager);
void find_frame_begin(void);
void find_frame_end(void);
diff --git a/monitor/main.c b/monitor/main.c
index 25de945446a9..1a7a25713de1 100644
--- a/monitor/main.c
+++ b/monitor/main.c
@@ -286,7 +286,7 @@ int main(int argc, char *argv[])
if (ellisys_server)
ellisys_enable(ellisys_server, ellisys_port);
- find_setup(false);
+ find_setup(false, use_pager);
control_reader(reader_path, use_pager);
return EXIT_SUCCESS;
@@ -310,7 +310,7 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
/* Watch for the key that brings the pager up */
- find_setup(true);
+ find_setup(true, use_pager);
exit_status = mainloop_run_with_signal(signal_callback, NULL);
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v1 6/6] doc/btmon: Document the pager choice
2026-09-17 20:45 [PATCH BlueZ v1 0/6] monitor: Search the frames with a pager Luiz Augusto von Dentz
` (4 preceding siblings ...)
2026-09-17 20:45 ` [PATCH BlueZ v1 5/6] monitor: Prefer fzf as the pager when one is not set Luiz Augusto von Dentz
@ 2026-09-17 20:45 ` Luiz Augusto von Dentz
5 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-17 20:45 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Describe that fzf is used when PAGER is not set, the options it is given,
and that it needs --ansi to render the colours when named explicitly.
The model drafted the text, which the author reviewed against the actual
behaviour.
Assisted-by: opencode:claude-opus-5
---
doc/btmon.rst | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/doc/btmon.rst b/doc/btmon.rst
index 163289bd1ef0..d01d563ba0e9 100644
--- a/doc/btmon.rst
+++ b/doc/btmon.rst
@@ -639,7 +639,9 @@ separates the lines within one and would otherwise show as a blank line at
the end of every entry.
Nothing is separated unless it was asked for, so a pager reading lines,
-such as ``less``, is unaffected and never shows the separator.
+such as ``less``, is unaffected and never shows the separator. Redirected
+output is never separated either unless ``--print0`` says so, since nothing
+is then reading it as records.
Searching a running capture
---------------------------
@@ -657,8 +659,17 @@ Whatever arrives while the pager is up is printed once it closes, so the
trace on the terminal has no gap. The capture is never paused, as anything
not read in time would be dropped by the kernel.
-The pager is taken from ``PAGER``, falling back to ``less``. Setting it to
-``cat`` or leaving it empty disables the pager, as elsewhere.
+The pager is taken from ``PAGER``. When that is not set and ``fzf`` is
+installed it is used instead of the plain pager, as it suits a trace far
+better. Wherever ``fzf`` is used it is given the options it needs, adding
+whichever of them are missing::
+
+ fzf --ansi --read0
+
+``--read0`` is what makes an entry a whole frame rather than a single line
+of one, and ``--ansi`` is what renders the colours instead of showing the
+escape sequences. Setting ``PAGER`` to ``cat`` or leaving it empty disables
+the pager, as elsewhere.
Frames are only collected when the output is a terminal, so a capture that
is piped or redirected behaves exactly as it always has. The terminal is
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* RE: monitor: Search the frames with a pager
2026-09-17 20:45 ` [PATCH BlueZ v1 1/6] monitor: Route the decoding output through a single function Luiz Augusto von Dentz
@ 2026-09-17 23:55 ` bluez.test.bot
0 siblings, 0 replies; 8+ messages in thread
From: bluez.test.bot @ 2026-09-17 23:55 UTC (permalink / raw)
To: linux-bluetooth, luiz.dentz
[-- Attachment #1: Type: text/plain, Size: 55928 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/series/1168010/
---Test result---
Test Summary:
CheckPatch FAIL 3.52 seconds
GitLint PASS 1.93 seconds
BuildEll PASS 19.31 seconds
BluezMake PASS 370.35 seconds
MakeCheck PASS 14.02 seconds
MakeDistcheck PASS 138.03 seconds
CheckValgrind PASS 228.89 seconds
CheckSmatch WARNING 287.39 seconds
bluezmakeextell PASS 92.46 seconds
TestFunctional FAIL 1079.05 seconds
IncrementalBuild PASS 420.46 seconds
ScanBuild PASS 1104.82 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[BlueZ,v1,1/6] monitor: Route the decoding output through a single function
WARNING:LONG_LINE: line length of 84 exceeds 80 columns
#163: FILE: monitor/analyze.c:373:
+ display_printf(" Found %s connection with handle %u\n", str, conn->handle);
WARNING:QUOTED_WHITESPACE_BEFORE_NEWLINE: unnecessary whitespace before a quoted newline
#204: FILE: monitor/analyze.c:503:
+ display_printf(" %lu control messages \n", dev->ctrl_msg);
WARNING:LONG_LINE: line length of 81 exceeds 80 columns
#528: FILE: monitor/control.c:124:
+ display_printf("@ Extended Index Removed: %u (%u)\n", ev->type, ev->bus);
WARNING:LONG_LINE_STRING: line length of 82 exceeds 80 columns
#551: FILE: monitor/control.c:163:
+ display_printf("* Malformed New Configuration Options control\n");
WARNING:LONG_LINE: line length of 84 exceeds 80 columns
#624: FILE: monitor/control.c:251:
+ display_printf("@ Local Name Changed: %s (%s)\n", ev->name, ev->short_name);
WARNING:LONG_LINE: line length of 88 exceeds 80 columns
#695: FILE: monitor/control.c:392:
+ display_printf("@ Device Disconnected: %s (%d) reason %u\n", str, ev->addr.type,
WARNING:LONG_LINE_STRING: line length of 82 exceeds 80 columns
#736: FILE: monitor/control.c:449:
+ display_printf("* Malformed User Confirmation Request control\n");
WARNING:LONG_LINE_STRING: line length of 81 exceeds 80 columns
#743: FILE: monitor/control.c:455:
+ display_printf("@ User Confirmation Request: %s (%d) hint %d value %d\n",
WARNING:LONG_LINE: line length of 83 exceeds 80 columns
#806: FILE: monitor/control.c:537:
+ display_printf("@ Discovering: 0x%2.2x (%d)\n", ev->discovering, ev->type);
WARNING:LONG_LINE: line length of 87 exceeds 80 columns
#923: FILE: monitor/control.c:702:
+ display_printf("@ Device Added: %s (%d) %d\n", str, ev->addr.type, ev->action);
WARNING:LONG_LINE_STRING: line length of 81 exceeds 80 columns
#948: FILE: monitor/control.c:737:
+ display_printf("* Malformed New Connection Parameter control\n");
WARNING:LONG_LINE_STRING: line length of 83 exceeds 80 columns
#957: FILE: monitor/control.c:747:
+ display_printf("@ New Conn Param: %s (%d) hint %d min 0x%4.4x max 0x%4.4x "
WARNING:LONG_LINE: line length of 85 exceeds 80 columns
#994: FILE: monitor/control.c:897:
+ display_printf("* Unknown control (code %d len %d)\n", opcode, size);
WARNING:LONG_LINE: line length of 82 exceeds 80 columns
#1012: FILE: monitor/control.c:1342:
+ display_printf("Unknown extended header type %u\n", type);
WARNING:LONG_LINE_STRING: line length of 86 exceeds 80 columns
#1020: FILE: monitor/control.c:1349:
+ display_printf("* Drops: cmd %u evt %u acl_tx %u acl_rx %u sco_tx %u "
ERROR:INITIALISED_STATIC: do not initialise statics to NULL
#1058: FILE: monitor/display.c:32:
+static FILE *display_out = NULL;
WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: Prefer __printf(1, 2) over __attribute__((format(printf, 1, 2)))
#1097: FILE: monitor/display.h:24:
+ __attribute__((format(printf, 1, 2)));
WARNING:LONG_LINE: line length of 81 exceeds 80 columns
#1148: FILE: monitor/l2cap.c:468:
+ display_printf(" TxSeq %d", (ctrl & L2CAP_EXT_CTRL_TXSEQ_MASK) >>
WARNING:TRAILING_SEMICOLON: macros should not use a trailing semicolon
#1288: FILE: monitor/packet.c:712:
+#define print_space(x) display_printf("%*c", (x), ' ');
WARNING:LONG_LINE: line length of 85 exceeds 80 columns
#1301: FILE: monitor/packet.c:925:
+ display_printf("%s%s\n", use_color() ? COLOR_TIMESTAMP : "", ts_str);
/home/runner/work/bluez/bluez/src/patch/14826833.patch total: 1 errors, 19 warnings, 1134 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/home/runner/work/bluez/bluez/src/patch/14826833.patch has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
monitor/packet.c:2288:26: warning: Variable length array is used.monitor/packet.c: note: in included file:monitor/bt.h:3924:52: warning: array of flexible structuresmonitor/bt.h:3912:40: warning: array of flexible structures
##############################
Test: TestFunctional - FAIL
Desc: Run test-functional
Output:
FAIL functional.test_bap::test_bap_unicast_set_transport_acquire[hosts7-vm3]: failed on setup with "pytest_bluezenv.rpc.RemoteTimeoutError: Connection recv timed out"
FAIL functional.test_bap::test_bap_unicast_set_transport_acquire[hosts7-vm3]: failed on teardown with "pytest_bluezenv.plugin.CoredumpWarning: Core dump: test-bluezenv-hosts7.0-bluetoothd-1789687730-67.core
/usr/bin/gdb: warning: Couldn't determine a path for the index cache directory.
[New LWP 67]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `/home/runner/work/bluez/bluez/src/src/src/bluetoothd --nodetach -f /run/bluetoo'.
Program terminated with signal SIGABRT, Aborted.
#0 __pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0) at ./nptl/pthread_kill.c:44
warning: 44 ./nptl/pthread_kill.c: No such file or directory
Thread 1 (Thread 0x7ff35da60900 (LWP 67)):
#0 __pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0) at ./nptl/pthread_kill.c:44
tid = <optimized out>
ret = 0
pd = <optimized out>
old_mask = {__val = {4412750543122677053}}
ret = <optimized out>
#1 __pthread_kill_internal (threadid=<optimized out>, signo=6) at ./nptl/pthread_kill.c:89
No locals.
#2 __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6) at ./nptl/pthread_kill.c:100
No locals.
#3 0x00007ff35e1bbb7e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
ret = <optimized out>
#4 0x00007ff35e19e8ec in __GI_abort () at ./stdlib/abort.c:77
act = {__sigaction_handler = {sa_handler = 0x0, sa_sigaction = 0x0}, sa_mask = {__val = {0, 136285141339808, 5205547781210355200, 140728911390080, 140728911390368, 140728911390224, 22, 140683229559760, 0, 140728911390160, 140683246405142, 140683216715776, 4096, 0, 5205547781210355200, 140683220897816}}, sa_flags = 1598976000, sa_restorer = 0x16}
#5 0x00007ff35edc6a0f in __sanitizer::Abort () at ../../../../src/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:165
No locals.
#6 0x00007ff35eeecc2d in __sanitizer::Die () at ../../../../src/libsanitizer/sanitizer_common/sanitizer_termination.cpp:58
No locals.
#7 0x00007ff35eec193c in __asan::ScopedInErrorReport::~ScopedInErrorReport (this=0x7ffe00c5e746) at ../../../../src/libsanitizer/asan/asan_report.cpp:221
buffer_copy = {buffer_ = {<__sanitizer::InternalMmapVectorNoCtor<char, false>> = {data_ = 0x7ff35d278000 '=' <repeats 65 times>, "\n==67==ERROR: AddressSanitizer: heap-use-after-free on address 0x7d635cee0208 at pc 0x56059bd2ad0c bp 0x7ffe00c5f3c0 sp 0x7ffe00c5f3b0\n"..., capacity_bytes_ = 4096, size_ = 3419}, <No data fields>}}
buffer_copy = <optimized out>
l = <optimized out>
#8 0x00007ff35eec0e02 in __asan::ReportGenericError (pc=94582089100556, bp=140728911393728, sp=sp@entry=140728911393712, addr=137865714336264, is_write=is_write@entry=false, access_size=8, fatal=true, exp=<optimized out>) at ../../../../src/libsanitizer/asan/asan_report.cpp:536
in_report = {error_report_lock_ = {<No data fields>}, static current_error_ = {kind = __asan::kErrorKindGeneric, {Base = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, DeadlySignal = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, signal = {siginfo = 0x7ffe00000002, context = 0x7d635cee0208, addr = 0, pc = 0, sp = 11162620003843, bp = 137865714336264, is_memory_access = 136, write_flag = __sanitizer::SignalContext::Unknown, is_true_faulting_addr = 128}}, DoubleFree = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, second_free_stack = 0x7ffe00000002, addr_description = {addr = 137865714336264, alloc_tid = 0, free_tid = 0, alloc_stack_id = 1539, free_stack_id = 2599, chunk_access = {bad_addr = 137865714336264, offset = 392, chunk_begin = 137865714335872, chunk_size = 752, user_requested_alignment = 8, access_type = 2, alloc_type = 1}}}, NewDeleteTypeMismatch = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, free_stack = 0x7ffe00000002, addr_description = {addr = 137865714336264, alloc_tid = 0, free_tid = 0, alloc_stack_id = 1539, free_stack_id = 2599, chunk_access = {bad_addr = 137865714336264, offset = 392, chunk_begin = 137865714335872, chunk_size = 752, user_requested_alignment = 8, access_type = 2, alloc_type = 1}}, delete_size = 140683245300511, delete_alignment = 1}, FreeNotMalloced = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, free_stack = 0x7ffe00000002, addr_description = {data = {kind = 1559101960, {shadow = {addr = 0, kind = __asan::kShadowKindLow, shadow_byte = 0 '\000'}, heap = {addr = 0, alloc_tid = 0, free_tid = 11162620003843, alloc_stack_id = 1559101960, free_stack_id = 32099, chunk_access = {bad_addr = 392, offset = 137865714335872, chunk_begin = 752, chunk_size = 140728911355912, user_requested_alignment = 2847, access_type = 2, alloc_type = 2}}, stack = {addr = 0, tid = 0, offset = 11162620003843, frame_pc = 137865714336264, access_size = 392, frame_descr = 0x7d635cee0080 "'\n"}, global = {addr = 0, static kMaxGlobals = 4, globals = {{beg = 0, size = 11162620003843, size_with_redzone = 137865714336264, name = 0x188 <error: Cannot access memory at address 0x188>, module_name = 0x7d635cee0080 "'\n", has_dynamic_init = 752, gcc_location = 0x7ffe00c56008, odr_indicator = 140683245300511}, {beg = 1, size = 137109800263360, size_with_redzone = 140728911393808, name = 0x7ff35eeb45d2 <___interceptor_malloc(__sanitizer::uptr)+130> "H\213U\350dH+\024%(", module_name = 0x3 <error: Cannot access memory at address 0x3>, has_dynamic_init = 130416287744, gcc_location = 0x7ffe00c5ebf0, odr_indicator = 2}, {beg = 140683246257680, size = 94582089659654, size_with_redzone = 140728911391904, name = 0x7 <error: Cannot access memory at address 0x7>, module_name = 0x7ff35ef62fc0 <__asan::instance> "", has_dynamic_init = 136422606391200, gcc_location = 0x7ffe00c5ec70, odr_indicator = 140683246357862}, {beg = 140728911391952, size = 6, size_with_redzone = 140683246972864, name = 0x7cb35cf18670 "\003\021", module_name = 0x7ffe00c5eca0 "\b", has_dynamic_init = 140683245324088, gcc_location = 0x78, odr_indicator = 137109800322672}}, reg_sites = {12971152, 32766, 1579802990, 32755}, access_size = 0, size = 12 '\f'}, wild = {addr = 0, access_size = 0}}}}}, AllocTypeMismatch = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, dealloc_stack = 0x7ffe00000002, alloc_type = 1559101960, dealloc_type = 32099, addr_description = {data = {kind = __asan::kAddressKindWild, {shadow = {addr = 0, kind = (__asan::kShadowKindGap | __asan::kShadowKindHigh), shadow_byte = 6 '\006'}, heap = {addr = 0, alloc_tid = 11162620003843, free_tid = 137865714336264, alloc_stack_id = 392, free_stack_id = 0, chunk_access = {bad_addr = 137865714335872, offset = 752, chunk_begin = 140728911355912, chunk_size = 140683245300511, user_requested_alignment = 1, access_type = 0, alloc_type = 0}}, stack = {addr = 0, tid = 11162620003843, offset = 137865714336264, frame_pc = 392, access_size = 137865714335872, frame_descr = 0x2f0 <error: Cannot access memory at address 0x2f0>}, global = {addr = 0, static kMaxGlobals = 4, globals = {{beg = 11162620003843, size = 137865714336264, size_with_redzone = 392, name = 0x7d635cee0080 "'\n", module_name = 0x2f0 <error: Cannot access memory at address 0x2f0>, has_dynamic_init = 140728911355912, gcc_location = 0x7ff35edcab1f <__asan::asan_malloc(unsigned long, __sanitizer::BufferedStackTrace*)+47>, odr_indicator = 1}, {beg = 137109800263360, size = 140728911393808, size_with_redzone = 140683246257618, name = 0x3 <error: Cannot access memory at address 0x3>, module_name = 0x1e5d6aa000 <error: Cannot access memory at address 0x1e5d6aa000>, has_dynamic_init = 140728911391728, gcc_location = 0x2, odr_indicator = 140683246257680}, {beg = 94582089659654, size = 140728911391904, size_with_redzone = 7, name = 0x7ff35ef62fc0 <__asan::instance> "", module_name = 0x7c135cfe47a0 "\003\021", has_dynamic_init = 140728911391856, gcc_location = 0x7ff35eeccd66 <__sanitizer::RunFreeHooks(void*)+86>, odr_indicator = 140728911391952}, {beg = 6, size = 140683246972864, size_with_redzone = 137109800322672, name = 0x7ffe00c5eca0 "\b", module_name = 0x7ff35edd0738 <__sanitizer::Quarantine<__asan::QuarantineCallback, __asan::AsanChunk>::Put(__sanitizer::QuarantineCache<__asan::QuarantineCallback>*, __asan::QuarantineCallback, __asan::AsanChunk*, unsigned long)+248> "H\203;", has_dynamic_init = 120, gcc_location = 0x7cb35cf18670, odr_indicator = 140728911391888}}, reg_sites = {1579802990, 32755, 0, 0}, access_size = 94582089100556, size = 192 '\300'}, wild = {addr = 0, access_size = 11162620003843}}}}}, MallocUsableSizeNotOwned = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, addr_description = {data = {kind = 1559101960, {shadow = {addr = 0, kind = __asan::kShadowKindLow, shadow_byte = 0 '\000'}, heap = {addr = 0, alloc_tid = 0, free_tid = 11162620003843, alloc_stack_id = 1559101960, free_stack_id = 32099, chunk_access = {bad_addr = 392, offset = 137865714335872, chunk_begin = 752, chunk_size = 140728911355912, user_requested_alignment = 2847, access_type = 2, alloc_type = 2}}, stack = {addr = 0, tid = 0, offset = 11162620003843, frame_pc = 137865714336264, access_size = 392, frame_descr = 0x7d635cee0080 "'\n"}, global = {addr = 0, static kMaxGlobals = 4, globals = {{beg = 0, size = 11162620003843, size_with_redzone = 137865714336264, name = 0x188 <error: Cannot access memory at address 0x188>, module_name = 0x7d635cee0080 "'\n", has_dynamic_init = 752, gcc_location = 0x7ffe00c56008, odr_indicator = 140683245300511}, {beg = 1, size = 137109800263360, size_with_redzone = 140728911393808, name = 0x7ff35eeb45d2 <___interceptor_malloc(__sanitizer::uptr)+130> "H\213U\350dH+\024%(", module_name = 0x3 <error: Cannot access memory at address 0x3>, has_dynamic_init = 130416287744, gcc_location = 0x7ffe00c5ebf0, odr_indicator = 2}, {beg = 140683246257680, size = 94582089659654, size_with_redzone = 140728911391904, name = 0x7 <error: Cannot access memory at address 0x7>, module_name = 0x7ff35ef62fc0 <__asan::instance> "", has_dynamic_init = 136422606391200, gcc_location = 0x7ffe00c5ec70, odr_indicator = 140683246357862}, {beg = 140728911391952, size = 6, size_with_redzone = 140683246972864, name = 0x7cb35cf18670 "\003\021", module_name = 0x7ffe00c5eca0 "\b", has_dynamic_init = 140683245324088, gcc_location = 0x78, odr_indicator = 137109800322672}}, reg_sites = {12971152, 32766, 1579802990, 32755}, access_size = 0, size = 12 '\f'}, wild = {addr = 0, access_size = 0}}}}}, SanitizerGetAllocatedSizeNotOwned = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, addr_description = {data = {kind = 1559101960, {shadow = {addr = 0, kind = __asan::kShadowKindLow, shadow_byte = 0 '\000'}, heap = {addr = 0, alloc_tid = 0, free_tid = 11162620003843, alloc_stack_id = 1559101960, free_stack_id = 32099, chunk_access = {bad_addr = 392, offset = 137865714335872, chunk_begin = 752, chunk_size = 140728911355912, user_requested_alignment = 2847, access_type = 2, alloc_type = 2}}, stack = {addr = 0, tid = 0, offset = 11162620003843, frame_pc = 137865714336264, access_size = 392, frame_descr = 0x7d635cee0080 "'\n"}, global = {addr = 0, static kMaxGlobals = 4, globals = {{beg = 0, size = 11162620003843, size_with_redzone = 137865714336264, name = 0x188 <error: Cannot access memory at address 0x188>, module_name = 0x7d635cee0080 "'\n", has_dynamic_init = 752, gcc_location = 0x7ffe00c56008, odr_indicator = 140683245300511}, {beg = 1, size = 137109800263360, size_with_redzone = 140728911393808, name = 0x7ff35eeb45d2 <___interceptor_malloc(__sanitizer::uptr)+130> "H\213U\350dH+\024%(", module_name = 0x3 <error: Cannot access memory at address 0x3>, has_dynamic_init = 130416287744, gcc_location = 0x7ffe00c5ebf0, odr_indicator = 2}, {beg = 140683246257680, size = 94582089659654, size_with_redzone = 140728911391904, name = 0x7 <error: Cannot access memory at address 0x7>, module_name = 0x7ff35ef62fc0 <__asan::instance> "", has_dynamic_init = 136422606391200, gcc_location = 0x7ffe00c5ec70, odr_indicator = 140683246357862}, {beg = 140728911391952, size = 6, size_with_redzone = 140683246972864, name = 0x7cb35cf18670 "\003\021", module_name = 0x7ffe00c5eca0 "\b", has_dynamic_init = 140683245324088, gcc_location = 0x78, odr_indicator = 137109800322672}}, reg_sites = {12971152, 32766, 1579802990, 32755}, access_size = 0, size = 12 '\f'}, wild = {addr = 0, access_size = 0}}}}}, CallocOverflow = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, count = 137865714336264, size = 0}, ReallocArrayOverflow = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, count = 137865714336264, size = 0}, PvallocOverflow = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, size = 137865714336264}, InvalidAllocationAlignment = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, alignment = 137865714336264}, InvalidAlignedAllocAlignment = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, size = 137865714336264, alignment = 0}, InvalidPosixMemalignAlignment = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, alignment = 137865714336264}, AllocationSizeTooBig = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, user_size = 137865714336264, total_size = 0, max_size = 0}, RssLimitExceeded = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002}, OutOfMemory = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, requested_size = 137865714336264}, StringFunctionMemoryRangesOverlap = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, length1 = 137865714336264, length2 = 0, addr1_description = {data = {kind = __asan::kAddressKindWild, {shadow = {addr = 11162620003843, kind = (unknown: 0x8), shadow_byte = 2 '\002'}, heap = {addr = 11162620003843, alloc_tid = 137865714336264, free_tid = 392, alloc_stack_id = 1559101568, free_stack_id = 32099, chunk_access = {bad_addr = 752, offset = 140728911355912, chunk_begin = 140683245300511, chunk_size = 1, user_requested_alignment = 3776, access_type = 1, alloc_type = 2}}, stack = {addr = 11162620003843, tid = 137865714336264, offset = 392, frame_pc = 137865714335872, access_size = 752, frame_descr = 0x7ffe00c56008 ""}, global = {addr = 11162620003843, static kMaxGlobals = 4, globals = {{beg = 137865714336264, size = 392, size_with_redzone = 137865714335872, name = 0x2f0 <error: Cannot access memory at address 0x2f0>, module_name = 0x7ffe00c56008 "", has_dynamic_init = 140683245300511, gcc_location = 0x1, odr_indicator = 137109800263360}, {beg = 140728911393808, size = 140683246257618, size_with_redzone = 3, name = 0x1e5d6aa000 <error: Cannot access memory at address 0x1e5d6aa000>, module_name = 0x7ffe00c5ebf0 "\020F\353^\363\177", has_dynamic_init = 2, gcc_location = 0x7ff35eeb4610 <___interceptor_malloc(__sanitizer::uptr)+192>, odr_indicator = 94582089659654}, {beg = 140728911391904, size = 7, size_with_redzone = 140683246972864, name = 0x7c135cfe47a0 "\003\021", module_name = 0x7ffe00c5ec70 "\220\354\305", has_dynamic_init = 140683246357862, gcc_location = 0x7ffe00c5ecd0, odr_indicator = 6}, {beg = 140683246972864, size = 137109800322672, size_with_redzone = 140728911391904, name = 0x7ff35edd0738 <__sanitizer::Quarantine<__asan::QuarantineCallback, __asan::AsanChunk>::Put(__sanitizer::QuarantineCache<__asan::QuarantineCallback>*, __asan::QuarantineCallback, __asan::AsanChunk*, unsigned long)+248> "H\203;", module_name = 0x78 <error: Cannot access memory at address 0x78>, has_dynamic_init = 137109800322672, gcc_location = 0x7ffe00c5ec90, odr_indicator = 140683233583470}}, reg_sites = {0, 0, 2614275340, 22021}, access_size = 140728911393728, size = 176 '\260'}, wild = {addr = 11162620003843, access_size = 137865714336264}}}}, addr2_description = {data = {kind = 8, {shadow = {addr = 140683246684055, kind = __asan::kShadowKindLow, shadow_byte = 253 '\375'}, heap = {addr = 140683246684055, alloc_tid = 140683243224320, free_tid = 140728911393376, alloc_stack_id = 1592264915, free_stack_id = 32755, chunk_access = {bad_addr = 140728911393376, offset = 1589639736, chunk_begin = 140728911393472, chunk_size = 140683243200086, user_requested_alignment = 384, access_type = 0, alloc_type = 0}}, stack = {addr = 140683246684055, tid = 140683243224320, offset = 140728911393376, frame_pc = 140683246045395, access_size = 140728911393376, frame_descr = 0x5ebffa38 <error: Cannot access memory at address 0x5ebffa38>}, global = {addr = 140683246684055, static kMaxGlobals = 4, globals = {{beg = 140683243224320, size = 140728911393376, size_with_redzone = 140683246045395, name = 0x7ffe00c5f260 "\200\001\356\\\003}", module_name = 0x5ebffa38 <error: Cannot access memory at address 0x5ebffa38>, has_dynamic_init = 140728911393472, gcc_location = 0x7ff35ebc9e56, odr_indicator = 137453397475712}, {beg = 140683243200036, size = 140728911393424, size_with_redzone = 6976585992864, name = 0x13 <error: Cannot access memory at address 0x13>, module_name = 0x2f475830 <error: Cannot access memory at address 0x2f475830>, has_dynamic_init = 140728911393456, gcc_location = 0x7c535cee0aa0, odr_indicator = 140728911393488}, {beg = 137109800322688, size = 137453397475712, size_with_redzone = 136560044747152, name = 0x56059bf0b5a0 <watch_destroy> "\363\017\036\372SH\211\373H\203\354\020H\205\377\017\2049\002", module_name = 0x7ff35ec2edce "I\211\305L9\360tJH\205\300tUH\213E\310dH+\004%(", has_dynamic_init = 137109800322688, gcc_location = 0x7ff35ec2edce, odr_indicator = 94582091068832}, {beg = 0, size = 140728911393584, size_with_redzone = 140683243613646, name = 0x7cf35cee1040 "\001", module_name = 0x7c335cef84d0 "\002", has_dynamic_init = 44, gcc_location = 0x0, odr_indicator = 136560044377304}}, reg_sites = {1559570856, 31795, 1559201008, 31795}, access_size = 94582091070702, size = 144 '\220'}, wild = {addr = 140683246684055, access_size = 140683243224320}}}}, function = 0x483dd220785db600 <error: Cannot access memory at address 0x483dd220785db600>}, StringFunctionSizeOverflow = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, addr_description = {data = {kind = 1559101960, {shadow = {addr = 0, kind = __asan::kShadowKindLow, shadow_byte = 0 '\000'}, heap = {addr = 0, alloc_tid = 0, free_tid = 11162620003843, alloc_stack_id = 1559101960, free_stack_id = 32099, chunk_access = {bad_addr = 392, offset = 137865714335872, chunk_begin = 752, chunk_size = 140728911355912, user_requested_alignment = 2847, access_type = 2, alloc_type = 2}}, stack = {addr = 0, tid = 0, offset = 11162620003843, frame_pc = 137865714336264, access_size = 392, frame_descr = 0x7d635cee0080 "'\n"}, global = {addr = 0, static kMaxGlobals = 4, globals = {{beg = 0, size = 11162620003843, size_with_redzone = 137865714336264, name = 0x188 <error: Cannot access memory at address 0x188>, module_name = 0x7d635cee0080 "'\n", has_dynamic_init = 752, gcc_location = 0x7ffe00c56008, odr_indicator = 140683245300511}, {beg = 1, size = 137109800263360, size_with_redzone = 140728911393808, name = 0x7ff35eeb45d2 <___interceptor_malloc(__sanitizer::uptr)+130> "H\213U\350dH+\024%(", module_name = 0x3 <error: Cannot access memory at address 0x3>, has_dynamic_init = 130416287744, gcc_location = 0x7ffe00c5ebf0, odr_indicator = 2}, {beg = 140683246257680, size = 94582089659654, size_with_redzone = 140728911391904, name = 0x7 <error: Cannot access memory at address 0x7>, module_name = 0x7ff35ef62fc0 <__asan::instance> "", has_dynamic_init = 136422606391200, gcc_location = 0x7ffe00c5ec70, odr_indicator = 140683246357862}, {beg = 140728911391952, size = 6, size_with_redzone = 140683246972864, name = 0x7cb35cf18670 "\003\021", module_name = 0x7ffe00c5eca0 "\b", has_dynamic_init = 140683245324088, gcc_location = 0x78, odr_indicator = 137109800322672}}, reg_sites = {12971152, 32766, 1579802990, 32755}, access_size = 0, size = 12 '\f'}, wild = {addr = 0, access_size = 0}}}}, size = 140728911393728}, BadParamsToAnnotateContiguousContainer = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, beg = 137865714336264, end = 0, old_mid = 0, new_mid = 11162620003843}, BadParamsToAnnotateDoubleEndedContiguousContainer = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, storage_beg = 137865714336264, storage_end = 0, old_container_beg = 0, old_container_end = 11162620003843, new_container_beg = 137865714336264, new_container_end = 392}, BadParamsToCopyContiguousContainerAnnotations = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, stack = 0x7ffe00000002, old_storage_beg = 137865714336264, old_storage_end = 0, new_storage_beg = 0, new_storage_end = 11162620003843}, ODRViolation = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, global1 = {beg = 140728898420738, size = 137865714336264, size_with_redzone = 0, name = 0x0, module_name = 0xa2700000603 <error: Cannot access memory at address 0xa2700000603>, has_dynamic_init = 137865714336264, gcc_location = 0x188, odr_indicator = 137865714335872}, global2 = {beg = 752, size = 140728911355912, size_with_redzone = 140683245300511, name = 0x1 <error: Cannot access memory at address 0x1>, module_name = 0x7cb35cf09ec0 "\200\a\356\\c}", has_dynamic_init = 140728911393808, gcc_location = 0x7ff35eeb45d2 <___interceptor_malloc(__sanitizer::uptr)+130>, odr_indicator = 3}, stack_id1 = 1567268864, stack_id2 = 30}, InvalidPointerPair = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, pc = 140728898420738, bp = 137865714336264, sp = 0, addr1_description = {data = {kind = __asan::kAddressKindWild, {shadow = {addr = 11162620003843, kind = (unknown: 0x8), shadow_byte = 2 '\002'}, heap = {addr = 11162620003843, alloc_tid = 137865714336264, free_tid = 392, alloc_stack_id = 1559101568, free_stack_id = 32099, chunk_access = {bad_addr = 752, offset = 140728911355912, chunk_begin = 140683245300511, chunk_size = 1, user_requested_alignment = 3776, access_type = 1, alloc_type = 2}}, stack = {addr = 11162620003843, tid = 137865714336264, offset = 392, frame_pc = 137865714335872, access_size = 752, frame_descr = 0x7ffe00c56008 ""}, global = {addr = 11162620003843, static kMaxGlobals = 4, globals = {{beg = 137865714336264, size = 392, size_with_redzone = 137865714335872, name = 0x2f0 <error: Cannot access memory at address 0x2f0>, module_name = 0x7ffe00c56008 "", has_dynamic_init = 140683245300511, gcc_location = 0x1, odr_indicator = 137109800263360}, {beg = 140728911393808, size = 140683246257618, size_with_redzone = 3, name = 0x1e5d6aa000 <error: Cannot access memory at address 0x1e5d6aa000>, module_name = 0x7ffe00c5ebf0 "\020F\353^\363\177", has_dynamic_init = 2, gcc_location = 0x7ff35eeb4610 <___interceptor_malloc(__sanitizer::uptr)+192>, odr_indicator = 94582089659654}, {beg = 140728911391904, size = 7, size_with_redzone = 140683246972864, name = 0x7c135cfe47a0 "\003\021", module_name = 0x7ffe00c5ec70 "\220\354\305", has_dynamic_init = 140683246357862, gcc_location = 0x7ffe00c5ecd0, odr_indicator = 6}, {beg = 140683246972864, size = 137109800322672, size_with_redzone = 140728911391904, name = 0x7ff35edd0738 <__sanitizer::Quarantine<__asan::QuarantineCallback, __asan::AsanChunk>::Put(__sanitizer::QuarantineCache<__asan::QuarantineCallback>*, __asan::QuarantineCallback, __asan::AsanChunk*, unsigned long)+248> "H\203;", module_name = 0x78 <error: Cannot access memory at address 0x78>, has_dynamic_init = 137109800322672, gcc_location = 0x7ffe00c5ec90, odr_indicator = 140683233583470}}, reg_sites = {0, 0, 2614275340, 22021}, access_size = 140728911393728, size = 176 '\260'}, wild = {addr = 11162620003843, access_size = 137865714336264}}}}, addr2_description = {data = {kind = 8, {shadow = {addr = 140683246684055, kind = __asan::kShadowKindLow, shadow_byte = 253 '\375'}, heap = {addr = 140683246684055, alloc_tid = 140683243224320, free_tid = 140728911393376, alloc_stack_id = 1592264915, free_stack_id = 32755, chunk_access = {bad_addr = 140728911393376, offset = 1589639736, chunk_begin = 140728911393472, chunk_size = 140683243200086, user_requested_alignment = 384, access_type = 0, alloc_type = 0}}, stack = {addr = 140683246684055, tid = 140683243224320, offset = 140728911393376, frame_pc = 140683246045395, access_size = 140728911393376, frame_descr = 0x5ebffa38 <error: Cannot access memory at address 0x5ebffa38>}, global = {addr = 140683246684055, static kMaxGlobals = 4, globals = {{beg = 140683243224320, size = 140728911393376, size_with_redzone = 140683246045395, name = 0x7ffe00c5f260 "\200\001\356\\\003}", module_name = 0x5ebffa38 <error: Cannot access memory at address 0x5ebffa38>, has_dynamic_init = 140728911393472, gcc_location = 0x7ff35ebc9e56, odr_indicator = 137453397475712}, {beg = 140683243200036, size = 140728911393424, size_with_redzone = 6976585992864, name = 0x13 <error: Cannot access memory at address 0x13>, module_name = 0x2f475830 <error: Cannot access memory at address 0x2f475830>, has_dynamic_init = 140728911393456, gcc_location = 0x7c535cee0aa0, odr_indicator = 140728911393488}, {beg = 137109800322688, size = 137453397475712, size_with_redzone = 136560044747152, name = 0x56059bf0b5a0 <watch_destroy> "\363\017\036\372SH\211\373H\203\354\020H\205\377\017\2049\002", module_name = 0x7ff35ec2edce "I\211\305L9\360tJH\205\300tUH\213E\310dH+\004%(", has_dynamic_init = 137109800322688, gcc_location = 0x7ff35ec2edce, odr_indicator = 94582091068832}, {beg = 0, size = 140728911393584, size_with_redzone = 140683243613646, name = 0x7cf35cee1040 "\001", module_name = 0x7c335cef84d0 "\002", has_dynamic_init = 44, gcc_location = 0x0, odr_indicator = 136560044377304}}, reg_sites = {1559570856, 31795, 1559201008, 31795}, access_size = 94582091070702, size = 144 '\220'}, wild = {addr = 140683246684055, access_size = 140683243224320}}}}}, Generic = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, addr_description = {data = {kind = __asan::kAddressKindHeap, {shadow = {addr = 137865714336264, kind = __asan::kShadowKindLow, shadow_byte = 0 '\000'}, heap = {addr = 137865714336264, alloc_tid = 0, free_tid = 0, alloc_stack_id = 1539, free_stack_id = 2599, chunk_access = {bad_addr = 137865714336264, offset = 392, chunk_begin = 137865714335872, chunk_size = 752, user_requested_alignment = 8, access_type = 2, alloc_type = 1}}, stack = {addr = 137865714336264, tid = 0, offset = 0, frame_pc = 11162620003843, access_size = 137865714336264, frame_descr = 0x188 <error: Cannot access memory at address 0x188>}, global = {addr = 137865714336264, static kMaxGlobals = 4, globals = {{beg = 0, size = 0, size_with_redzone = 11162620003843, name = 0x7d635cee0208 "", module_name = 0x188 <error: Cannot access memory at address 0x188>, has_dynamic_init = 137865714335872, gcc_location = 0x2f0, odr_indicator = 140728911355912}, {beg = 140683245300511, size = 1, size_with_redzone = 137109800263360, name = 0x7ffe00c5f410 "\0202\275\233\005V", module_name = 0x7ff35eeb45d2 <___interceptor_malloc(__sanitizer::uptr)+130> "H\213U\350dH+\024%(", has_dynamic_init = 3, gcc_location = 0x1e5d6aa000, odr_indicator = 140728911391728}, {beg = 2, size = 140683246257680, size_with_redzone = 94582089659654, name = 0x7ffe00c5eca0 "\b", module_name = 0x7 <error: Cannot access memory at address 0x7>, has_dynamic_init = 140683246972864, gcc_location = 0x7c135cfe47a0, odr_indicator = 140728911391856}, {beg = 140683246357862, size = 140728911391952, size_with_redzone = 6, name = 0x7ff35ef62fc0 <__asan::instance> "", module_name = 0x7cb35cf18670 "\003\021", has_dynamic_init = 140728911391904, gcc_location = 0x7ff35edd0738 <__sanitizer::Quarantine<__asan::QuarantineCallback, __asan::AsanChunk>::Put(__sanitizer::QuarantineCache<__asan::QuarantineCallback>*, __asan::QuarantineCallback, __asan::AsanChunk*, unsigned long)+248>, odr_indicator = 120}}, reg_sites = {1559332464, 31923, 12971152, 32766}, access_size = 140683233583470, size = 0 '\000'}, wild = {addr = 137865714336264, access_size = 0}}}}, pc = 94582089100556, bp = 140728911393728, sp = 140728911393712, access_size = 8, bug_descr = 0x7ff35ef1c797 "heap-use-after-free", is_write = false, shadow_val = 253 '\375'}}}, halt_on_error_ = true}
error = {<__asan::ErrorBase> = {scariness = {score = 51, descr = "8-byte-read-heap-use-after-free\000\363{\000\000\377\000\000\000\000\000\000\000`\027\000\234\005V\000\000f\315\354^\363\177\000\0000\350\305\000\376\177\000\000\002\000\000\000\000\000\000\000\300/\366^\363\177\000\000\020\373\356\\s|\000\000\000\350\305\000\376\177\000\0008\a\335^\363\177\000\000^\000\000\000\000\000\000\000\020\373\356\\s|\000\000\320\240j]\363\177\000\000 \350\305\000\376\177\000\000 \373\356\\s|\000\000q\000\000\000\000\000\000\000\220\360\305\000\376\177\000\000^\000\000\000\000\000\000\000P\360\305\000\376\177\000\000\3013\353^\363\177\000\000\3429\371\233\005V\000\000\270\377\377\377"...}, tid = 0}, addr_description = {data = {kind = __asan::kAddressKindHeap, {shadow = {addr = 137865714336264, kind = __asan::kShadowKindLow, shadow_byte = 0 '\000'}, heap = {addr = 137865714336264, alloc_tid = 0, free_tid = 0, alloc_stack_id = 1539, free_stack_id = 2599, chunk_access = {bad_addr = 137865714336264, offset = 392, chunk_begin = 137865714335872, chunk_size = 752, user_requested_alignment = 8, access_type = 2, alloc_type = 1}}, stack = {addr = 137865714336264, tid = 0, offset = 0, frame_pc = 11162620003843, access_size = 137865714336264, frame_descr = 0x188 <error: Cannot access memory at address 0x188>}, global = {addr = 137865714336264, static kMaxGlobals = 4, globals = {{beg = 0, size = 0, size_with_redzone = 11162620003843, name = 0x7d635cee0208 "", module_name = 0x188 <error: Cannot access memory at address 0x188>, has_dynamic_init = 137865714335872, gcc_location = 0x2f0, odr_indicator = 140728911355912}, {beg = 140683245300511, size = 1, size_with_redzone = 137109800263360, name = 0x7ffe00c5f410 "\0202\275\233\005V", module_name = 0x7ff35eeb45d2 <___interceptor_malloc(__sanitizer::uptr)+130> "H\213U\350dH+\024%(", has_dynamic_init = 3, gcc_location = 0x1e5d6aa000, odr_indicator = 140728911391728}, {beg = 2, size = 140683246257680, size_with_redzone = 94582089659654, name = 0x7ffe00c5eca0 "\b", module_name = 0x7 <error: Cannot access memory at address 0x7>, has_dynamic_init = 140683246972864, gcc_location = 0x7c135cfe47a0, odr_indicator = 140728911391856}, {beg = 140683246357862, size = 140728911391952, size_with_redzone = 6, name = 0x7ff35ef62fc0 <__asan::instance> "", module_name = 0x7cb35cf18670 "\003\021", has_dynamic_init = 140728911391904, gcc_location = 0x7ff35edd0738 <__sanitizer::Quarantine<__asan::QuarantineCallback, __asan::AsanChunk>::Put(__sanitizer::QuarantineCache<__asan::QuarantineCallback>*, __asan::QuarantineCallback, __asan::AsanChunk*, unsigned long)+248>, odr_indicator = 120}}, reg_sites = {1559332464, 31923, 12971152, 32766}, access_size = 140683233583470, size = 0 '\000'}, wild = {addr = 137865714336264, access_size = 0}}}}, pc = 94582089100556, bp = 140728911393728, sp = 140728911393712, access_size = 8, bug_descr = 0x7ff35ef1c797 "heap-use-after-free", is_write = false, shadow_val = 253 '\375'}
#9 0x00007ff35eec0f8d in __asan::ReportGenericError (pc=<optimized out>, bp=bp@entry=140728911393728, sp=sp@entry=140728911393712, addr=<optimized out>, is_write=is_write@entry=false, access_size=access_size@entry=8, exp=<optimized out>, fatal=true) at ../../../../src/libsanitizer/asan/asan_report.cpp:536
in_report = <optimized out>
error = <optimized out>
enable_fp = <optimized out>
#10 0x00007ff35eec23f9 in __asan::__asan_report_load8 (addr=<optimized out>) at ../../../../src/libsanitizer/asan/asan_rtl.cpp:131
bp = 140728911393728
pc = <optimized out>
local_stack = 140728911393840
sp = 140728911393712
#11 0x000056059bd2ad0c in device_get_adapter (device=<optimized out>) at src/device.c:6900
No locals.
#12 0x000056059bbd324f in find_cig_session (data=0x7cb35cf07c40, match_data=0x7bf35bd847b0) at profiles/audio/bap.c:2500
session = 0x7cb35cf07c40
info = 0x7bf35bd847b0
#13 0x000056059bdb1ee1 in queue_find (queue=<optimized out>, function=function@entry=0x56059bbd3210 <find_cig_session>, match_data=match_data@entry=0x7bf35bd847b0) at src/shared/queue.c:230
entry = 0x7c135cf57090
#14 0x000056059bbd9d14 in find_cig_enumerate (data=0x7cb35cf09ec0) at profiles/audio/bap.c:2539
info = <optimized out>
#15 bap_update_cigs_cb (user_data=0x7cb35cf09ec0) at profiles/audio/bap.c:2688
data = 0x7cb35cf09ec0
cigs = <optimized out>
unset = <optimized out>
#16 0x00007ff35ebccb9b in ?? () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
No symbol table info available.
#17 0x00007ff35ebce1d7 in ?? () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
No symbol table info available.
#18 0x00007ff35ebce577 in g_main_loop_run () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
No symbol table info available.
#19 0x000056059bf0ddc9 in mainloop_run () at src/shared/mainloop-glib.c:65
No locals.
#20 0x000056059bf0e6fb in mainloop_run_with_signal (func=func@entry=0x56059bd73840 <signal_callback>, user_data=user_data@entry=0x0) at src/shared/mainloop-notify.c:196
data = 0x7c235cee3490
io = 0x7c335cef9b10
ret = <optimized out>
#21 0x000056059ba8c2fb in main (argc=<optimized out>, argv=<optimized out>) at src/main.c:1713
context = <optimized out>
err = <optimized out>
sdp_mtu = 0
sdp_flags = <optimized out>
gdbus_flags = <optimized out>
__func__ = "main""
https://github.com/bluez/bluez/pull/2543
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-17 23:55 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-17 20:45 [PATCH BlueZ v1 0/6] monitor: Search the frames with a pager Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 1/6] monitor: Route the decoding output through a single function Luiz Augusto von Dentz
2026-09-17 23:55 ` monitor: Search the frames with a pager bluez.test.bot
2026-09-17 20:45 ` [PATCH BlueZ v1 2/6] monitor: Separate the frames for a pager reading records Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 3/6] monitor: Hand the captured frames to the pager on Ctrl-R Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 4/6] doc/btmon: Document searching the frames Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 5/6] monitor: Prefer fzf as the pager when one is not set Luiz Augusto von Dentz
2026-09-17 20:45 ` [PATCH BlueZ v1 6/6] doc/btmon: Document the pager choice Luiz Augusto von Dentz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox