/src/wireshark/epan/dissectors/packet-gdb.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* packet-gdb.c |
2 | | * Routines for dissection of GDB's Remote Serial Protocol |
3 | | * |
4 | | * Copyright 2014, Martin Kaiser <martin@kaiser.cx> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | /* |
14 | | * The GDB Remote Serial Protocol is used between an instance of the |
15 | | * GNU Debugger and a remote target such as an embedded system. |
16 | | * It can be run over TCP/IP or a serial line, we support only TCP/IP. |
17 | | * |
18 | | * The protocol specification is in Annex E of the GDB user manual |
19 | | * http://www.gnu.org/software/gdb/documentation/ |
20 | | * |
21 | | */ |
22 | | |
23 | | #include "config.h" |
24 | | |
25 | | #include <epan/packet.h> |
26 | | #include <epan/tvbparse.h> |
27 | | |
28 | | enum { |
29 | | GDB_TOK_ACK, |
30 | | GDB_TOK_START, |
31 | | GDB_TOK_PAYLOAD, |
32 | | GDB_TOK_END, |
33 | | GDB_TOK_CHKSUM |
34 | | }; |
35 | | |
36 | | static const value_string gdb_ack[] = { |
37 | | { '+', "Transmission successful" }, |
38 | | { '-', "Transmission failed" }, |
39 | | { 0, NULL } |
40 | | }; |
41 | | |
42 | | |
43 | | void proto_register_gdb(void); |
44 | | void proto_reg_handoff_gdb(void); |
45 | | |
46 | | static dissector_handle_t gdb_handle; |
47 | | |
48 | | static int proto_gdb; |
49 | | |
50 | | static int ett_gdb; |
51 | | |
52 | | static int hf_gdb_ack; |
53 | | static int hf_gdb_start; |
54 | | static int hf_gdb_payload; |
55 | | static int hf_gdb_end; |
56 | | static int hf_gdb_chksum; |
57 | | |
58 | | static tvbparse_wanted_t *want; |
59 | | |
60 | | static void |
61 | | dissect_gdb_token(void *tvbparse_data, const void *wanted_data, tvbparse_elem_t *tok) |
62 | 0 | { |
63 | 0 | proto_tree *tree; |
64 | 0 | unsigned token; |
65 | |
|
66 | 0 | if (!tok) /* XXX - is this check necessary? */ |
67 | 0 | return; |
68 | | |
69 | 0 | tree = (proto_tree *)tvbparse_data; |
70 | 0 | token = GPOINTER_TO_UINT(wanted_data); |
71 | | |
72 | | /* XXX - check that tok->len is what we expect? */ |
73 | 0 | switch (token) { |
74 | 0 | case GDB_TOK_ACK: |
75 | 0 | proto_tree_add_item(tree, hf_gdb_ack, |
76 | 0 | tok->tvb, tok->offset, tok->len, ENC_ASCII|ENC_NA); |
77 | 0 | break; |
78 | 0 | case GDB_TOK_START: |
79 | 0 | proto_tree_add_item(tree, hf_gdb_start, |
80 | 0 | tok->tvb, tok->offset, tok->len, ENC_ASCII); |
81 | 0 | break; |
82 | 0 | case GDB_TOK_PAYLOAD: |
83 | 0 | proto_tree_add_item(tree, hf_gdb_payload, |
84 | 0 | tok->tvb, tok->offset, tok->len, ENC_NA); |
85 | 0 | break; |
86 | 0 | case GDB_TOK_END: |
87 | 0 | proto_tree_add_item(tree, hf_gdb_end, |
88 | 0 | tok->tvb, tok->offset, tok->len, ENC_ASCII); |
89 | 0 | break; |
90 | 0 | case GDB_TOK_CHKSUM: |
91 | 0 | proto_tree_add_item(tree, hf_gdb_chksum, |
92 | 0 | tok->tvb, tok->offset, tok->len, ENC_ASCII); |
93 | 0 | break; |
94 | 0 | default: |
95 | 0 | break; |
96 | 0 | } |
97 | 0 | } |
98 | | |
99 | 14 | static void init_gdb_parser(void) { |
100 | 14 | tvbparse_wanted_t *want_ack; |
101 | 14 | tvbparse_wanted_t *want_start; |
102 | 14 | tvbparse_wanted_t *want_payload; |
103 | 14 | tvbparse_wanted_t *want_end; |
104 | 14 | tvbparse_wanted_t *want_chksum; |
105 | | |
106 | 14 | want_ack = tvbparse_chars(-1, 1, 1, "+-", |
107 | 14 | GUINT_TO_POINTER(GDB_TOK_ACK), NULL, dissect_gdb_token); |
108 | 14 | want_start = tvbparse_chars(-1, 1, 1, "$", |
109 | 14 | GUINT_TO_POINTER(GDB_TOK_START), NULL, dissect_gdb_token); |
110 | 14 | want_payload = tvbparse_not_chars(-1, 1, 0, "$#", |
111 | 14 | GUINT_TO_POINTER(GDB_TOK_PAYLOAD), NULL, dissect_gdb_token); |
112 | 14 | want_end = tvbparse_chars(-1, 1, 1, "#", |
113 | 14 | GUINT_TO_POINTER(GDB_TOK_END), NULL, dissect_gdb_token); |
114 | 14 | want_chksum = tvbparse_chars(-1, 2, 2, "0123456789abcdefABCDEF", |
115 | 14 | GUINT_TO_POINTER(GDB_TOK_CHKSUM), NULL, dissect_gdb_token); |
116 | | |
117 | 14 | want = tvbparse_set_seq(-1, NULL, NULL, NULL, |
118 | 14 | tvbparse_some(-1, 0, 1, NULL, NULL, NULL, want_ack), |
119 | 14 | want_start, want_payload, want_end, want_chksum, NULL); |
120 | 14 | } |
121 | | |
122 | | |
123 | | static void |
124 | | dissect_gdb_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) |
125 | 0 | { |
126 | 0 | proto_item *ti; |
127 | 0 | proto_tree *gdb_tree; |
128 | 0 | tvbparse_t *tt; |
129 | |
|
130 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "GDB"); |
131 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
132 | |
|
133 | 0 | ti = proto_tree_add_protocol_format(tree, proto_gdb, |
134 | 0 | tvb, 0, tvb_reported_length(tvb), "GDB Remote Serial Protocol"); |
135 | 0 | gdb_tree = proto_item_add_subtree(ti, ett_gdb); |
136 | | |
137 | | /* XXX support multiple sub-trees */ |
138 | 0 | tt = tvbparse_init(pinfo->pool, tvb, 0, -1, (void *)gdb_tree, NULL); |
139 | |
|
140 | 0 | while(tvbparse_get(tt, want)) { |
141 | 0 | ; |
142 | 0 | } |
143 | 0 | } |
144 | | |
145 | | |
146 | | static int |
147 | | dissect_gdb_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
148 | 0 | { |
149 | 0 | int offset=0, offset_start; |
150 | 0 | int pos; |
151 | 0 | unsigned packet_len; |
152 | 0 | tvbuff_t *packet_tvb; |
153 | |
|
154 | 0 | while (tvb_captured_length_remaining(tvb, offset) > 0) { |
155 | 0 | packet_tvb = NULL; |
156 | 0 | offset_start = offset; |
157 | 0 | pos = tvb_find_uint8(tvb, offset, -1, '#'); |
158 | 0 | if (pos != -1) { |
159 | 0 | offset += pos; |
160 | 0 | offset++; /* skip the hash sign */ |
161 | | /* to have a complete packet, we need another two bytes |
162 | | for the checksum */ |
163 | 0 | if (tvb_bytes_exist(tvb, offset, 2)) { |
164 | 0 | offset += 2; |
165 | 0 | packet_len = offset-offset_start; |
166 | 0 | packet_tvb = tvb_new_subset_length(tvb, offset_start, |
167 | 0 | packet_len); |
168 | 0 | } |
169 | 0 | } |
170 | |
|
171 | 0 | if (packet_tvb) |
172 | 0 | dissect_gdb_packet(tvb, pinfo, tree); |
173 | 0 | else { |
174 | 0 | pinfo->desegment_offset = offset; |
175 | 0 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; |
176 | 0 | return tvb_captured_length(tvb); |
177 | 0 | } |
178 | 0 | } |
179 | 0 | return tvb_captured_length(tvb); |
180 | 0 | } |
181 | | |
182 | | |
183 | | void |
184 | | proto_register_gdb(void) |
185 | 14 | { |
186 | 14 | static hf_register_info hf[] = { |
187 | 14 | { &hf_gdb_ack, |
188 | 14 | { "Acknowledge", "gdb.ack", FT_CHAR, BASE_HEX, |
189 | 14 | VALS(gdb_ack), 0, NULL, HFILL } }, |
190 | 14 | { &hf_gdb_start, |
191 | 14 | { "Start character", "gdb.start", FT_STRING, BASE_NONE, |
192 | 14 | NULL, 0, NULL, HFILL } }, |
193 | 14 | { &hf_gdb_payload, |
194 | 14 | { "Payload", "gdb.payload", FT_BYTES, BASE_NONE, |
195 | 14 | NULL, 0, NULL, HFILL } }, |
196 | 14 | { &hf_gdb_end, |
197 | 14 | { "Terminating character", "gdb.end", FT_STRING, BASE_NONE, |
198 | 14 | NULL, 0, NULL, HFILL } }, |
199 | 14 | { &hf_gdb_chksum, |
200 | 14 | { "Checksum", "gdb.chksum", FT_STRING, BASE_NONE, |
201 | 14 | NULL, 0, NULL, HFILL } } |
202 | 14 | }; |
203 | | |
204 | 14 | static int *ett[] = { |
205 | 14 | &ett_gdb |
206 | 14 | }; |
207 | | |
208 | | |
209 | 14 | proto_gdb = proto_register_protocol("GDB Remote Serial Protocol", "GDB remote", "gdb"); |
210 | 14 | gdb_handle = register_dissector("gdb", dissect_gdb_tcp, proto_gdb); |
211 | | |
212 | 14 | proto_register_field_array(proto_gdb, hf, array_length(hf)); |
213 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
214 | | |
215 | 14 | init_gdb_parser(); |
216 | 14 | } |
217 | | |
218 | | |
219 | | void |
220 | | proto_reg_handoff_gdb(void) |
221 | 14 | { |
222 | 14 | dissector_add_for_decode_as_with_preference("tcp.port", gdb_handle); |
223 | 14 | } |
224 | | |
225 | | /* |
226 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
227 | | * |
228 | | * Local variables: |
229 | | * c-basic-offset: 4 |
230 | | * tab-width: 8 |
231 | | * indent-tabs-mode: nil |
232 | | * End: |
233 | | * |
234 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
235 | | * :indentSize=4:tabSize=8:noTabs=true: |
236 | | */ |