The Breakpoints section lists every breakpoint the debugger knows about, with two columns:
source:line for the line of the
breakpoint.
Rows whose source file no longer exists on disk are drawn with a warning icon, gray text, and a disabled Active checkbox; their tooltip reads File not found: <path> so you can spot stale entries that the loader will never resolve.
Breakpoints are created and removed in several ways:
Shift-clicking the gutter on an existing breakpoint
toggles only its active state (red ↔ gray) without removing
it; on a line with no breakpoint, Shift-click adds a
disabled (gray) breakpoint, which is handy for pre-arming a
line you want to break on later without paying the line-hook
cost until you activate it. The gutter’s tooltip surfaces both
behaviors.
Ctrl+Shift+B to toggle a breakpoint
on the current line (same as the context-menu shortcuts).
Ctrl+F10 does the same. The
target clears itself the first time execution reaches it, and
is also discarded by Continue or any Step. The target
survives across dissector returns, so a line that is only
reached on a later packet still pauses.
Looking for conditional breakpoints, hit counts, or logpoints? Edit the Location cell of a breakpoint row to attach any of those — see Section 14.8.1, “Conditions, hit counts, and logpoints”.
Double-clicking a row in the Breakpoints table opens the corresponding file in the editor and jumps to the line.
The section header carries four small controls to the right of the title rule, in left-to-right order:
Ctrl+Shift+B shortcut.
- — Remove Breakpoint (Delete). Removes the
selected rows; disabled when nothing is selected.
⚙ — Edit Breakpoint. Opens the inline editor on the
focused row (or the first selected row), the same as
double-clicking the Location cell or pressing F2.
Ⓧ — Remove All Breakpoints (Ctrl+Shift+F9).
Disabled when the Breakpoints list is empty.
The Breakpoints table supports Ctrl / Shift click
for multi-row selection. A right-click context menu groups its
entries by scope — first the actions that target the row under
the cursor, then the actions that target the whole table:
F2. Disabled on
stale rows whose target file is no longer loaded.
hit_count and the {delta}
reference timestamp for the clicked row. Enabled when the row
has a hit-count target or a counter greater than zero.
Delete /
Backspace also work).
hit_count and the {delta}
reference timestamp on every row that currently has a non-zero
counter.
Ⓧ control in the section header (labeled with
Ctrl+Shift+F9 in the menu; the shortcut works from
anywhere in the dialog).
Breakpoints survive Wireshark restarts. Adding a breakpoint automatically turns the debugger on if it was off — running with no line hook cannot trigger a pause.
The Location cell of a breakpoint row is editable (double-click,
F2, or right-click → Edit) and lets you attach one of
three extras to the breakpoint. A white core inside the breakpoint
dot — in the Breakpoints list and in the editor gutter — marks
rows that carry an extra:
Hit Count — gate the pause on a hit-counter. 0 disables
the gate. A small dropdown next to the integer picks the
comparison mode:
|
|
Pause on every hit from N onwards — inclusive of the N-th hit (default; "skip the first N-1, then pause forever"). |
|
|
Pause on hits N, 2N, 3N, … — sample a noisy loop without stopping on every iteration. |
|
|
One-shot. Pause on the N-th hit and deactivate the breakpoint so subsequent hits go through. The slot is consumed the moment the counter reaches N, even if the row’s Expression evaluates falsy or the row is a logpoint that emits and resumes — the row deactivates either way. The row’s Active checkbox visibly clears AND the runtime counter resets to zero in the same step, so re-ticking Active is enough to arm the next N-hit cycle without a separate Reset Hit Count. |
The counter is per breakpoint and is not persisted across Wireshark restarts.
The Log Message template uses {…} placeholders. {{ and
}} produce literal { / }. Anything inside {} that is not
one of the reserved tags below is evaluated as a Lua expression
in the paused frame and converted to text with the same coercion
tostring() performs; per-placeholder evaluation errors
substitute <error: …> without aborting the line.
The reserved tags below shadow any same-named Lua local /
upvalue / global. To log a Lua variable that happens to share a
name with a tag, wrap it: {tostring(filename)}.
Origin
|
|
Source file path (canonicalized). |
|
|
Last path component of |
|
|
1-based line number of the breakpoint. |
|
|
Running function’s name ( |
|
|
Frame kind: |
Counters and scope
|
|
This breakpoint’s cumulative hit counter — the number
of times the line has been reached since the row was created
or the counter was last reset. The counter advances on every
line hit, including hits skipped by the hit-count gate or a
falsy Expression; the log line itself only emits on hits the
gates pass, so the value rendered is the counter at the firing
moment (e.g. |
|
|
Lua-frame stack depth at the fire site. |
|
|
|
Time
|
|
Local wall-clock |
|
|
Local |
|
|
Unix time, seconds with millisecond fraction. |
|
|
Unix time as integer milliseconds. |
|
|
Milliseconds since the debugger was last attached. |
|
|
Milliseconds since this breakpoint last fired
( |
The mini-blocks below resolve against the names defined by the
printer.lua postdissector in Section 14.3, “Getting Started”:
locals tvb, pinfo, tree, offset inside printer.dissector,
upvalues sessions, last_seen, opcode_names, handshake,
ip_src_F, tcp_flags_F. Drop a breakpoint on any line of
printer.dissector and edit its Location cell to attach the
extras shown.
Expression — gate the pause on a Lua predicate.
-- Pause only after frame 100: pinfo.number > 100 -- Only on the first dissection of a frame: not pinfo.visited -- Only TLS in either direction: pinfo.dst_port == 443 or pinfo.src_port == 443 -- Frames whose IP source we have seen before: last_seen[tostring(pinfo.src)] ~= nil -- Bail-out invariant: pause if a length assumption breaks: tvb:len() < 20
A runtime error inside the expression is treated as false and
shows a warning icon on the row, so a typo or a nil index
silently disables the pause instead of stopping execution. See
Section 14.6.3, “Expression patterns” for the full menu of shapes
the same evaluator accepts.
Hit Count — gate the pause on a counter.
The integer field carries N; the dropdown next to it picks the comparison mode. The block below sketches the three shapes the gate can take (each line reads as "mode N" — the mode is the dropdown selection, N is what you type into the integer field):
from 10 -- ignore the first 9 hits, pause from hit 10 on
(default mode; "skip the warm-up")
every 100 -- sample a tight per-packet loop: pause on hits
100, 200, 300, …
once 5 -- one-shot debug: pause on hit 5 and clear the
row's Active checkbox; tick it again to re-arm
0 -- disable the gate (any mode); same as clearing
the field
The counter is per breakpoint and per Wireshark session. It is
preserved across edits to the Expression, the Hit Count
target or mode, and the Log Message — tuning the threshold
or switching from from to every mid-run will not throw away
the count you were watching, with one exception: lowering the
target below the current counter rolls the counter back to
0 so the breakpoint can resume waiting for "the next N
hits" instead of pausing on every line. Right-click the row
and choose Reset Hit Count — or Reset All Hit Counts on
the empty area of the table — to zero it explicitly. The
counter is not persisted across Wireshark restarts. Hit Count,
Expression, and Log Message on the same row run
in a strict order: hit-count → Expression → Log Message.
The hit-count gate runs first; only when it passes is the
Expression evaluated; only when the Expression is truthy
(or absent) does the Log Message emit and the row pause. So a
logpoint with a condition stays silent while the condition is
false, and an every 100 logpoint with tvb:len() > 1500 only
logs on the matching every-hundredth packet.
Log Message — show where the line hit.
{filename}:{line}
{basename}:{line} in {function}
{filename}:{line} ({what}) hits={hits} depth={depth}
[{thread}] {function}:{line}
{basename} is the readable form of {filename} — the script’s
filename without its directory, useful when most logs come from
one or two scripts and the absolute path is just noise.
{function} is ? for anonymous, tail, and main-chunk frames;
{what} (Lua / C / main / tail) disambiguates them.
{thread} is main for
the main coroutine and coro@<ptr> otherwise — handy when a
dissector is called from a tap callback that runs on its own
coroutine.
Log Message — wall-clock and intervals.
[{timestamp}] hit
[{datetime}] entered {function}
{epoch_ms} -- frame seen, ms since the Unix epoch
{elapsed} ms since the debugger was attached
loop iteration {hits} took {delta} ms since the previous fire
Use {timestamp} for short interactive sessions and {datetime}
for long-running captures where you may cross midnight. {delta}
reports 0 on the very first fire (and after Reset Hit Count /
Reset All Hit Counts), so a "took 0 ms" line in the log marks a
fresh counter rather than an instant fire.
Log Message — mixing tags with Lua expressions.
Anything inside {} that isn’t a reserved tag is evaluated as a
Lua expression in the paused frame and converted to text with the
same coercion tostring() performs, just like a Watch row.
frame {pinfo.number}: {tostring(pinfo.src)} -> {tostring(pinfo.dst)}
bytes_left={tvb:len() - offset} at {filename}:{line}
flags=0x{string.format("%02x", tvb:range(13, 1):uint())}
{tostring(pinfo.src)} last seen at frame {last_seen[tostring(pinfo.src)] or "never"}
{datetime} hit #{hits}: ports {pinfo.src_port}->{pinfo.dst_port}
Wireshark userdata classes (Address, Pinfo, Tvb, …) expose
their canonical text via __tostring, so wrap them in
tostring(…) instead of relying on a :tostring() method (the
class doesn’t have one). { is the only character that needs
escaping; {{ and }} produce literal braces:
state = {{ src={tostring(pinfo.src)}, dst={tostring(pinfo.dst)} }}
A per-placeholder runtime error becomes <error: …> inline, so
one bad expression in a long template doesn’t drop the rest of
the line. Edit the row’s Location cell to clear the bad
placeholder.
| Logpoints on every packet of a large capture | |
|---|---|
|
A logpoint that matches every packet of a multi-thousand-frame capture can fire thousands of times per second. The debugger coalesces those fires onto the GUI thread in a single drain per event-loop tick, and the Evaluate output keeps only the last ~5000 lines (older lines are evicted as new ones arrive), so the dialog stays responsive — but each fire still runs the template formatter on the Lua thread. To keep per-packet logpoints cheap on big captures:
|