This is an automated email from the ASF dual-hosted git repository.
bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 90e7283feb gdb pretty printer for HttpSM history (#12255)
90e7283feb is described below
commit 90e7283feb35dfa46410d3210f41f1270877e953
Author: Brian Neradt <[email protected]>
AuthorDate: Wed May 28 16:31:07 2025 -0500
gdb pretty printer for HttpSM history (#12255)
This adds a gdb pretty-printer for the HttpSM history (or other History)
variables. It does the following:
* Prints the entries in order, handling the wrapping of the circular
buffer as necessary,
* Prints a human readable version of the events.
* Filers out set_next_state and the state_api_call* functions since they
don't seem to add much value.
Example (run from a frame in HttpSM):
```
(gdb) source ~bneradt/gdb-helpers.py
(gdb) p history
$50 = History(capacity=65, history_pos=124, num_entries=65) = {
HttpSM.cc:5025 do_cache_lookup_and_read
TS_EVENT_NONE (0) reent= 22,
HttpSM.cc:2088 state_send_server_request_header
TS_EVENT_VCONN_WRITE_COMPLETE (103) reent= 1,
HttpSM.cc:6361 do_setup_client_request_body_tunnel
NO_EVENT (34463) reent= 1,
HttpSM.cc:1903 state_read_server_response_header
TS_EVENT_VCONN_EOS (104) reent= 1,
HttpCacheSM.cc:104 state_cache_open_read
TS_EVENT_CACHE_OPEN_READ_FAILED (1103) reent= -31073,
HttpSM.cc:2568 state_cache_open_read
TS_EVENT_CACHE_OPEN_READ_FAILED (1103) reent= 15,
HttpSM.cc:5025 do_cache_lookup_and_read
TS_EVENT_NONE (0) reent= 14,
HttpSM.cc:1770 state_http_server_open
TS_EVENT_VCONN_EOS (104) reent= 1
}
```
---
tools/gdb-helpers.py | 300 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 299 insertions(+), 1 deletion(-)
diff --git a/tools/gdb-helpers.py b/tools/gdb-helpers.py
index def0dcd974..5df12f284c 100644
--- a/tools/gdb-helpers.py
+++ b/tools/gdb-helpers.py
@@ -27,15 +27,313 @@
#
# Type `atspr` by itself for a list of printables.
#
+# The History printing works best with `set print array on`.
+#
import gdb
+import re
import socket
import struct
from curses.ascii import isgraph
-# return memory for an ats string address and length
+class HistoryEntryPrinter:
+ """Pretty-printer for a HistoryEntry"""
+
+ def __init__(self, val):
+ self.val = val
+
+ @staticmethod
+ def event_value_to_description(event_num: int) -> str:
+ """Convert event value to a human-readable description.
+ :param event_num: The event number.
+ :return: A string description of the event.
+ """
+ if event_num == 60000:
+ return 'TS_EVENT_HTTP_CONTINUE'
+ elif event_num == 0:
+ return 'TS_EVENT_NONE'
+ elif event_num == 1:
+ return 'TS_EVENT_IMMEDIATE'
+ elif event_num == 2:
+ return 'TS_EVENT_TIMEOUT'
+ elif event_num == 3:
+ return 'TS_EVENT_ERROR'
+ elif event_num == 4:
+ return 'TS_EVENT_CONTINUE'
+ elif event_num == 34463:
+ return 'NO_EVENT'
+
+ elif event_num == 100:
+ return 'TS_EVENT_VCONN_READ_READY'
+ elif event_num == 101:
+ return 'TS_EVENT_VCONN_WRITE_READY'
+ elif event_num == 102:
+ return 'TS_EVENT_VCONN_READ_COMPLETE'
+ elif event_num == 103:
+ return 'TS_EVENT_VCONN_WRITE_COMPLETE'
+ elif event_num == 104:
+ return 'TS_EVENT_VCONN_EOS'
+ elif event_num == 105:
+ return 'TS_EVENT_VCONN_INACTIVITY_TIMEOUT'
+ elif event_num == 106:
+ return 'TS_EVENT_VCONN_ACTIVE_TIMEOUT'
+ elif event_num == 107:
+ return 'TS_EVENT_VCONN_START'
+ elif event_num == 108:
+ return 'TS_EVENT_VCONN_CLOSE'
+ elif event_num == 109:
+ return 'TS_EVENT_VCONN_OUTBOUND_START'
+ elif event_num == 110:
+ return 'TS_EVENT_VCONN_OUTBOUND_CLOSE'
+ elif event_num == 107:
+ return 'TS_EVENT_VCONN_PRE_ACCEPT'
+
+ elif event_num == 200:
+ return 'TS_EVENT_NET_CONNECT'
+ elif event_num == 201:
+ return 'TS_EVENT_NET_CONNECT_FAILED'
+ elif event_num == 202:
+ return 'TS_EVENT_NET_ACCEPT'
+ elif event_num == 204:
+ return 'TS_EVENT_NET_ACCEPT_FAILED'
+
+ elif event_num == 206:
+ return 'TS_EVENT_INTERNAL_206'
+ elif event_num == 207:
+ return 'TS_EVENT_INTERNAL_207'
+ elif event_num == 208:
+ return 'TS_EVENT_INTERNAL_208'
+ elif event_num == 209:
+ return 'TS_EVENT_INTERNAL_209'
+ elif event_num == 210:
+ return 'TS_EVENT_INTERNAL_210'
+ elif event_num == 211:
+ return 'TS_EVENT_INTERNAL_211'
+ elif event_num == 212:
+ return 'TS_EVENT_INTERNAL_212'
+
+ elif event_num == 500:
+ return 'TS_EVENT_HOST_LOOKUP'
+ elif event_num == 1102:
+ return 'TS_EVENT_CACHE_OPEN_READ'
+ elif event_num == 1103:
+ return 'TS_EVENT_CACHE_OPEN_READ_FAILED'
+ elif event_num == 1108:
+ return 'TS_EVENT_CACHE_OPEN_WRITE'
+ elif event_num == 1109:
+ return 'TS_EVENT_CACHE_OPEN_WRITE_FAILED'
+ elif event_num == 1112:
+ return 'TS_EVENT_CACHE_REMOVE'
+ elif event_num == 1113:
+ return 'TS_EVENT_CACHE_REMOVE_FAILED'
+ elif event_num == 1120:
+ return 'TS_EVENT_CACHE_SCAN'
+ elif event_num == 1121:
+ return 'TS_EVENT_CACHE_SCAN_FAILED'
+ elif event_num == 1122:
+ return 'TS_EVENT_CACHE_SCAN_OBJECT'
+ elif event_num == 1123:
+ return 'TS_EVENT_CACHE_SCAN_OPERATION_BLOCKED'
+ elif event_num == 1124:
+ return 'TS_EVENT_CACHE_SCAN_OPERATION_FAILED'
+ elif event_num == 1125:
+ return 'TS_EVENT_CACHE_SCAN_DONE'
+ elif event_num == 1126:
+ return 'TS_EVENT_CACHE_LOOKUP'
+ elif event_num == 1127:
+ return 'TS_EVENT_CACHE_READ'
+ elif event_num == 1128:
+ return 'TS_EVENT_CACHE_DELETE'
+ elif event_num == 1129:
+ return 'TS_EVENT_CACHE_WRITE'
+ elif event_num == 1130:
+ return 'TS_EVENT_CACHE_WRITE_HEADER'
+ elif event_num == 1131:
+ return 'TS_EVENT_CACHE_CLOSE'
+ elif event_num == 1132:
+ return 'TS_EVENT_CACHE_LOOKUP_READY'
+ elif event_num == 1133:
+ return 'TS_EVENT_CACHE_LOOKUP_COMPLETE'
+ elif event_num == 1134:
+ return 'TS_EVENT_CACHE_READ_READY'
+ elif event_num == 1135:
+ return 'TS_EVENT_CACHE_READ_COMPLETE'
+
+ elif event_num == 1200:
+ return 'TS_EVENT_INTERNAL_1200'
+
+ elif event_num == 2000:
+ return 'TS_EVENT_SSL_SESSION_GET'
+ elif event_num == 2001:
+ return 'TS_EVENT_SSL_SESSION_NEW'
+ elif event_num == 2002:
+ return 'TS_EVENT_SSL_SESSION_REMOVE'
+
+ elif event_num == 3900:
+ return 'TS_EVENT_AIO_DONE'
+
+ elif event_num == 60000:
+ return 'TS_EVENT_HTTP_CONTINUE'
+ elif event_num == 60001:
+ return 'TS_EVENT_HTTP_ERROR'
+ elif event_num == 60002:
+ return 'TS_EVENT_HTTP_READ_REQUEST_HDR'
+ elif event_num == 60003:
+ return 'TS_EVENT_HTTP_OS_DNS'
+ elif event_num == 60004:
+ return 'TS_EVENT_HTTP_SEND_REQUEST_HDR'
+ elif event_num == 60005:
+ return 'TS_EVENT_HTTP_READ_CACHE_HDR'
+ elif event_num == 60006:
+ return 'TS_EVENT_HTTP_READ_RESPONSE_HDR'
+ elif event_num == 60007:
+ return 'TS_EVENT_HTTP_SEND_RESPONSE_HDR'
+ elif event_num == 60008:
+ return 'TS_EVENT_HTTP_REQUEST_TRANSFORM'
+ elif event_num == 60009:
+ return 'TS_EVENT_HTTP_RESPONSE_TRANSFORM'
+ elif event_num == 60010:
+ return 'TS_EVENT_HTTP_SELECT_ALT'
+ elif event_num == 60011:
+ return 'TS_EVENT_HTTP_TXN_START'
+ elif event_num == 60012:
+ return 'TS_EVENT_HTTP_TXN_CLOSE'
+ elif event_num == 60013:
+ return 'TS_EVENT_HTTP_SSN_START'
+ elif event_num == 60014:
+ return 'TS_EVENT_HTTP_SSN_CLOSE'
+ elif event_num == 60015:
+ return 'TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE'
+ elif event_num == 60016:
+ return 'TS_EVENT_HTTP_PRE_REMAP'
+ elif event_num == 60017:
+ return 'TS_EVENT_HTTP_POST_REMAP'
+ elif event_num == 60018:
+ return 'TS_EVENT_HTTP_REQUEST_BUFFER_COMPLETE'
+
+ elif event_num == 60100:
+ return 'TS_EVENT_LIFECYCLE_PORTS_INITIALIZED'
+ elif event_num == 60101:
+ return 'TS_EVENT_LIFECYCLE_PORTS_READY'
+ elif event_num == 60102:
+ return 'TS_EVENT_LIFECYCLE_CACHE_READY'
+ elif event_num == 60103:
+ return 'TS_EVENT_LIFECYCLE_SERVER_SSL_CTX_INITIALIZED'
+ elif event_num == 60104:
+ return 'TS_EVENT_LIFECYCLE_CLIENT_SSL_CTX_INITIALIZED'
+ elif event_num == 60105:
+ return 'TS_EVENT_LIFECYCLE_MSG'
+ elif event_num == 60106:
+ return 'TS_EVENT_LIFECYCLE_TASK_THREADS_READY'
+ elif event_num == 60107:
+ return 'TS_EVENT_LIFECYCLE_SHUTDOWN'
+
+ elif event_num == 60200:
+ return 'TS_EVENT_INTERNAL_60200'
+ elif event_num == 60201:
+ return 'TS_EVENT_INTERNAL_60201'
+ elif event_num == 60202:
+ return 'TS_EVENT_INTERNAL_60202'
+ elif event_num == 60203:
+ return 'TS_EVENT_SSL_CERT'
+ elif event_num == 60204:
+ return 'TS_EVENT_SSL_SERVERNAME'
+ elif event_num == 60205:
+ return 'TS_EVENT_SSL_VERIFY_SERVER'
+ elif event_num == 60206:
+ return 'TS_EVENT_SSL_VERIFY_CLIENT'
+ elif event_num == 60207:
+ return 'TS_EVENT_SSL_CLIENT_HELLO'
+ elif event_num == 60208:
+ return 'TS_EVENT_SSL_SECRET'
+
+ elif event_num == 60300:
+ return 'TS_EVENT_MGMT_UPDATE'
+
+ else:
+ return f'Unknown event {event_num}'
+
+ def to_string(self):
+ loc = self.val['location']
+
+ file = loc['file'].string()
+ line = int(loc['line'])
+ base_name = file.split('/')[-1]
+ location_description = f'{base_name}:{line}'
+
+ function = loc['func'].string() if loc['func'] else ''
+ event = int(self.val['event'])
+ event_name = self.event_value_to_description(event)
+ event_description = f'{event_name} ({event})'
+
+ reent = int(self.val['reentrancy'])
+ return f"{location_description:<25} {function:<50}
{event_description:<55} reent={reent:>7}"
+
+
+class HistoryPrinter:
+ '''Pretty-printer for History<Count>.
+
+ This is in the HttpSM class as 'history', for example.
+ '''
+
+ def __init__(self, val):
+ self.val = val
+ t = val.type.strip_typedefs().unqualified()
+ name = t.name or ''
+ m = re.match(r'.*History<([0-9]+)>', name)
+ self.capacity = int(m.group(1)) if m else None
+ self.history_position = int(val['history_pos'])
+
+ def to_string(self):
+ num_entries = self.capacity if self.history_position >= self.capacity
else self.history_position
+ return f"History(capacity={self.capacity},
history_pos={self.history_position}, num_entries={num_entries})"
+
+ def children(self):
+ '''Print the history entries from earliest to latest.
+
+ This handles the circular buffer nature of the history.
+ '''
+ has_wrapped = self.history_position >= self.capacity
+ first_entry = self.history_position % self.capacity if has_wrapped
else 0
+ num_entries = self.capacity if has_wrapped else self.history_position
+
+ history_entries = self.val['history']
+ for i in range(num_entries):
+ index = (first_entry + i) % self.capacity
+ history_entry = history_entries[index]
+ location = history_entry['location']
+ func = location['func'].string()
+ if 'state_api_call' in func or 'set_next_state' in func:
+ # These are generally not useful.
+ continue
+ yield f"[{i}]", history_entry
+
+ # Set display_hint.
+ def display_hint(self):
+ '''Indicate that History is an array-like object.'''
+ return 'array'
+
+
+def lookup_history_printer(val):
+ t = val.type.strip_typedefs().unqualified()
+ name = t.name or ''
+ # Handle plain HistoryEntry
+ if name == 'HistoryEntry':
+ return HistoryEntryPrinter(val)
+ # Handle History<Count> template
+ if re.match(r'.*History<\d+>', name):
+ return HistoryPrinter(val)
+ return None
+
+
+# Register our pretty-printers.
+if hasattr(gdb, 'pretty_printers'):
+ gdb.pretty_printers.append(lookup_history_printer)
+
+
+# return memory for an ats string address and length
def ats_str(addr, addr_len):
if addr_len == 0:
return ''