[Lldb-commits] [lldb] [lldb] Fix qSpeedTest radix mistake, make number parsings explicit (PR #211495)
Jason Molenda via lldb-commits
lldb-commits at lists.llvm.org
Thu Jul 23 01:29:03 PDT 2026
https://github.com/jasonmolenda created https://github.com/llvm/llvm-project/pull/211495
The documentation for qSpeedTest says
```
send packet: qSpeedTest:response_size:response-size;
read packet: data:<response data>
response-size is a hex encoded unsigned number up to 64 bits in size.
```
debugserver implements qSpeedTest as per this documentation, but lldb sends the number in decimal (base 10), and lldb-server parses it as base 10. I changed lldb and lldb-server to base 16. This is a maintenance command used by lldb developers exclusivley, so IMO I'm not handling a migration for old/new servers or defining a new packet or key. I was running some packet transmission tests with debugserver and noticed debugserver was sending much larger packets than requested; that's the kind of failure you see when there is a mismatch.
I audited all uses of `getAsInteger()` that pass a 0 for the radix, meaning auto-detect the radix, in the gdb-remote dir and changed nearly all of them to specify either base 10 or base 16. There were two places where we were using auto-sensing on a base 16 number (and no "0x" prefix), which would parse incorrectly if an [a-f] letter did not occur.
There is one use of `getAsInteger(0,...)` that is still in place, for pasing the `qRegisterInfo` eh-frame/dwarf register numbers. Our documentation for these keys specifies that they may be base 10 or base 16 if prefixed with 0x. This is unlike anywhere else in gdb remote serial protocol, and smells like something I probably stuck in there 15+ years ago because I've never liked the ambiguity about number bases in the protocol and I made this half-hearted stab at encouraging use of "0x".
It is always fun to see the inconsistencies as you review multiple packets. qProcessInfo returns keys like pid/gid/ppid in base 16. qfProcessInfo returns the same keys in base 10. qHostInfo returns cputype/cpusubtype (a Mach-O way of specifying a target cpu) in base 10, qProcessInfo returns the same keys in base 16. There's so many of these kinds of little inconsistencies :/
>From b2d516f0cafba1bddd52a490586fda5173e3f2f8 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Thu, 23 Jul 2026 01:07:20 -0700
Subject: [PATCH] [lldb] Fix qSpeedTest radix mistake, make number parsings
explicit
The documentation for qSpeedTest says
```
send packet: qSpeedTest:response_size:response-size;
read packet: data:<response data>
response-size is a hex encoded unsigned number up to 64 bits in size.
```
debugserver implements qSpeedTest as per this documentation, but
lldb sends the number in decimal (base 10), and lldb-server parses
it that way too. I changed lldb and lldb-server to base 16. This
is a maintenance command used by lldb developers exclusivley, so
IMO I'm not handling a migration for old/new servers or defining a
new packet or key. I was running some packet transmission tests with
debugserver and noticed lldb was receiving much larger packets than
it requested, that's the kind of failure you see when there is a
mismatch.
I audited all uses of `getAsInteger()` that pass a 0 for the radix,
meaning auto-detect the radix, and changed nearly all of them to
specify either base 10 or base 16. There were two cases where
packets were sending a base 16 number without a "0x" prefix and
the auto-sensing radix would do the wrong thing if an [a-f] letter
didn't occur in the number.
There is one use of `getAsInteger(0,...)` that is still in place,
for pasing the `qRegisterInfo` eh-frame/dwarf register numbers.
Our documentation for these keys specifies that they may be base
10 or base 16 if prefixed with 0x. This is unlike anywhere else in
gdb remote serial protocol, and smells like something I probably
stuck in there 15+ years ago because I've never liked the ambiguity
about number bases in the protocol and I made this half-hearted
stab at encouraging use of "0x".
It is always fun to see the inconsistencies as you review multiple
packets. qProcessInfo returns keys like pid/gid/ppid in base 16.
qfProcessInfo returns the same keys in base 10. qHostInfo returns
cputype/cpusubtype (a Mach-O way of specifying a target cpu) in
base 10, qProcessInfo returns the same keys in base 16. There's
so many of these kinds of little inconsistencies :/
---
.../GDBRemoteCommunicationClient.cpp | 40 +++++++++----------
.../GDBRemoteCommunicationServerCommon.cpp | 14 +++----
.../GDBRemoteCommunicationServerPlatform.cpp | 2 +-
.../Process/gdb-remote/ProcessGDBRemote.cpp | 16 ++++----
4 files changed, 36 insertions(+), 36 deletions(-)
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index a3fe6661737a4..8ae50f1f83c3f 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -1179,7 +1179,7 @@ bool GDBRemoteCommunicationClient::GetGDBServerVersion() {
} else if (name == "version") {
llvm::StringRef major, minor;
std::tie(major, minor) = value.split('.');
- if (!major.getAsInteger(0, m_gdb_server_version))
+ if (!major.getAsInteger(10, m_gdb_server_version))
success = true;
}
}
@@ -1347,11 +1347,11 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) {
while (response.GetNameColonValue(name, value)) {
if (name == "cputype") {
// exception type in big endian hex
- if (!value.getAsInteger(0, cpu))
+ if (!value.getAsInteger(10, cpu))
++num_keys_decoded;
} else if (name == "cpusubtype") {
// exception count in big endian hex
- if (!value.getAsInteger(0, sub))
+ if (!value.getAsInteger(10, sub))
++num_keys_decoded;
} else if (name == "arch") {
arch_name = std::string(value);
@@ -1391,17 +1391,17 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) {
if (byte_order != eByteOrderInvalid)
++num_keys_decoded;
} else if (name == "ptrsize") {
- if (!value.getAsInteger(0, pointer_byte_size))
+ if (!value.getAsInteger(10, pointer_byte_size))
++num_keys_decoded;
} else if (name == "addressing_bits") {
- if (!value.getAsInteger(0, m_low_mem_addressing_bits)) {
+ if (!value.getAsInteger(10, m_low_mem_addressing_bits)) {
++num_keys_decoded;
}
} else if (name == "high_mem_addressing_bits") {
- if (!value.getAsInteger(0, m_high_mem_addressing_bits))
+ if (!value.getAsInteger(10, m_high_mem_addressing_bits))
++num_keys_decoded;
} else if (name == "low_mem_addressing_bits") {
- if (!value.getAsInteger(0, m_low_mem_addressing_bits))
+ if (!value.getAsInteger(10, m_low_mem_addressing_bits))
++num_keys_decoded;
} else if (name == "os_version" ||
name == "version") // Older debugserver binaries used
@@ -1423,14 +1423,14 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) {
++num_keys_decoded;
} else if (name == "default_packet_timeout") {
uint32_t timeout_seconds;
- if (!value.getAsInteger(0, timeout_seconds)) {
+ if (!value.getAsInteger(10, timeout_seconds)) {
m_default_packet_timeout = seconds(timeout_seconds);
SetPacketTimeout(m_default_packet_timeout);
++num_keys_decoded;
}
} else if (name == "vm-page-size") {
int page_size;
- if (!value.getAsInteger(0, page_size)) {
+ if (!value.getAsInteger(10, page_size)) {
m_target_vm_page_size = page_size;
++num_keys_decoded;
}
@@ -2144,27 +2144,27 @@ bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse(
while (response.GetNameColonValue(name, value)) {
if (name == "pid") {
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
- value.getAsInteger(0, pid);
+ value.getAsInteger(10, pid);
process_info.SetProcessID(pid);
} else if (name == "ppid") {
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
- value.getAsInteger(0, pid);
+ value.getAsInteger(10, pid);
process_info.SetParentProcessID(pid);
} else if (name == "uid") {
uint32_t uid = UINT32_MAX;
- value.getAsInteger(0, uid);
+ value.getAsInteger(10, uid);
process_info.SetUserID(uid);
} else if (name == "euid") {
uint32_t uid = UINT32_MAX;
- value.getAsInteger(0, uid);
+ value.getAsInteger(10, uid);
process_info.SetEffectiveUserID(uid);
} else if (name == "gid") {
uint32_t gid = UINT32_MAX;
- value.getAsInteger(0, gid);
+ value.getAsInteger(10, gid);
process_info.SetGroupID(gid);
} else if (name == "egid") {
uint32_t gid = UINT32_MAX;
- value.getAsInteger(0, gid);
+ value.getAsInteger(10, gid);
process_info.SetEffectiveGroupID(gid);
} else if (name == "triple") {
StringExtractor extractor(value);
@@ -2199,9 +2199,9 @@ bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse(
is_arg0 = false;
}
} else if (name == "cputype") {
- value.getAsInteger(0, cpu);
+ value.getAsInteger(10, cpu);
} else if (name == "cpusubtype") {
- value.getAsInteger(0, sub);
+ value.getAsInteger(10, sub);
} else if (name == "vendor") {
vendor = std::string(value);
} else if (name == "ostype") {
@@ -2570,7 +2570,7 @@ bool GDBRemoteCommunicationClient::GetGroupName(uint32_t gid,
static void MakeSpeedTestPacket(StreamString &packet, uint32_t send_size,
uint32_t recv_size) {
packet.Clear();
- packet.Printf("qSpeedTest:response_size:%i;data:", recv_size);
+ packet.Printf("qSpeedTest:response_size:%x;data:", recv_size);
uint32_t bytes_left = send_size;
while (bytes_left > 0) {
if (bytes_left >= 26) {
@@ -2772,9 +2772,9 @@ bool GDBRemoteCommunicationClient::LaunchGDBServer(
llvm::StringRef value;
while (response.GetNameColonValue(name, value)) {
if (name == "port")
- value.getAsInteger(0, port);
+ value.getAsInteger(10, port);
else if (name == "pid")
- value.getAsInteger(0, pid);
+ value.getAsInteger(10, pid);
else if (name.compare("socket_name") == 0) {
StringExtractor extractor(value);
extractor.GetHexByteString(socket_name);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index d710dfec95873..2ebbb35a56bb6 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -365,32 +365,32 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo(
return SendErrorResponse(2);
} else if (key == "pid") {
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
- if (value.getAsInteger(0, pid))
+ if (value.getAsInteger(10, pid))
return SendErrorResponse(2);
match_info.GetProcessInfo().SetProcessID(pid);
} else if (key == "parent_pid") {
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
- if (value.getAsInteger(0, pid))
+ if (value.getAsInteger(10, pid))
return SendErrorResponse(2);
match_info.GetProcessInfo().SetParentProcessID(pid);
} else if (key == "uid") {
uint32_t uid = UINT32_MAX;
- if (value.getAsInteger(0, uid))
+ if (value.getAsInteger(10, uid))
return SendErrorResponse(2);
match_info.GetProcessInfo().SetUserID(uid);
} else if (key == "gid") {
uint32_t gid = UINT32_MAX;
- if (value.getAsInteger(0, gid))
+ if (value.getAsInteger(10, gid))
return SendErrorResponse(2);
match_info.GetProcessInfo().SetGroupID(gid);
} else if (key == "euid") {
uint32_t uid = UINT32_MAX;
- if (value.getAsInteger(0, uid))
+ if (value.getAsInteger(10, uid))
return SendErrorResponse(2);
match_info.GetProcessInfo().SetEffectiveUserID(uid);
} else if (key == "egid") {
uint32_t gid = UINT32_MAX;
- if (value.getAsInteger(0, gid))
+ if (value.getAsInteger(10, gid))
return SendErrorResponse(2);
match_info.GetProcessInfo().SetEffectiveGroupID(gid);
} else if (key == "all_users") {
@@ -480,7 +480,7 @@ GDBRemoteCommunicationServerCommon::Handle_qSpeedTest(
bool success = packet.GetNameColonValue(key, value);
if (success && key == "response_size") {
uint32_t response_size = 0;
- if (!value.getAsInteger(0, response_size)) {
+ if (!value.getAsInteger(16, response_size)) {
if (response_size == 0)
return SendOKResponse();
StreamString response;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
index eaed4e6742824..0bcfea5e9c68e 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
@@ -164,7 +164,7 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
if (name == "port") {
// Make the Optional valid so we can use its value
port = 0;
- value.getAsInteger(0, *port);
+ value.getAsInteger(10, *port);
}
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 20fa9f03d0a07..7d4d870ccbbbc 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -540,10 +540,10 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
} else if (name == "alt-name") {
reg_info.alt_name.SetString(value);
} else if (name == "bitsize") {
- if (!value.getAsInteger(0, reg_info.byte_size))
+ if (!value.getAsInteger(10, reg_info.byte_size))
reg_info.byte_size /= CHAR_BIT;
} else if (name == "offset") {
- value.getAsInteger(0, reg_info.byte_offset);
+ value.getAsInteger(10, reg_info.byte_offset);
} else if (name == "encoding") {
const Encoding encoding = Args::StringToEncoding(value);
if (encoding != eEncodingInvalid)
@@ -2515,7 +2515,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
.Default(eQueueKindUnknown);
queue_vars_valid = queue_kind != eQueueKindUnknown;
} else if (key.compare("qserialnum") == 0) {
- if (!value.getAsInteger(0, queue_serial_number))
+ if (!value.getAsInteger(10, queue_serial_number))
queue_vars_valid = true;
} else if (key.compare("reason") == 0) {
reason = std::string(value);
@@ -2541,7 +2541,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
std::tie(addr_str, bytes_str) = value.split('=');
if (!addr_str.empty() && !bytes_str.empty()) {
lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS;
- if (!addr_str.getAsInteger(0, mem_cache_addr)) {
+ if (!addr_str.getAsInteger(16, mem_cache_addr)) {
StringExtractor bytes(bytes_str);
const size_t byte_size = bytes.GetBytesLeft() / 2;
WritableDataBufferSP data_buffer_sp(
@@ -2594,17 +2594,17 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
description = std::string(ostr.GetString());
} else if (key.compare("addressing_bits") == 0) {
uint64_t addressing_bits;
- if (!value.getAsInteger(0, addressing_bits)) {
+ if (!value.getAsInteger(10, addressing_bits)) {
addressable_bits.SetAddressableBits(addressing_bits);
}
} else if (key.compare("low_mem_addressing_bits") == 0) {
uint64_t addressing_bits;
- if (!value.getAsInteger(0, addressing_bits)) {
+ if (!value.getAsInteger(10, addressing_bits)) {
addressable_bits.SetLowmemAddressableBits(addressing_bits);
}
} else if (key.compare("high_mem_addressing_bits") == 0) {
uint64_t addressing_bits;
- if (!value.getAsInteger(0, addressing_bits)) {
+ if (!value.getAsInteger(10, addressing_bits)) {
addressable_bits.SetHighmemAddressableBits(addressing_bits);
}
} else if (key == "added-binaries") {
@@ -6022,7 +6022,7 @@ std::string ProcessGDBRemote::HarmonizeThreadIdsForProfileData(
if (profileDataExtractor.GetNameColonValue(usec_name, usec_value)) {
if (usec_name == "thread_used_usec") {
has_used_usec = true;
- usec_value.getAsInteger(0, curr_used_usec);
+ usec_value.getAsInteger(10, curr_used_usec);
} else {
// We didn't find what we want, it is probably an older version. Bail
// out.
More information about the lldb-commits
mailing list