1 /* packet-logcat-text.c
2 * Routines for Android Logcat text formats
4 * Copyright 2014, Michal Orynicz for Tieto Corporation
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <stdio.h> /* for sscanf() */
17 #include "epan/packet.h"
18 #include "epan/expert.h"
19 #include "epan/exported_pdu.h"
21 #include "wiretap/logcat_text.h"
23 extern const value_string priority_vals
[];
25 static int proto_logcat_text
;
27 static int hf_logcat_text_pid
;
28 static int hf_logcat_text_tid
;
29 static int hf_logcat_text_timestamp
;
30 static int hf_logcat_text_priority
;
31 static int hf_logcat_text_tag
;
32 static int hf_logcat_text_log
;
34 static int ett_logcat
;
36 static expert_field ei_malformed_time
;
37 static expert_field ei_malformed_token
;
39 static dissector_handle_t logcat_text_brief_handle
;
40 static dissector_handle_t logcat_text_tag_handle
;
41 static dissector_handle_t logcat_text_process_handle
;
42 static dissector_handle_t logcat_text_time_handle
;
43 static dissector_handle_t logcat_text_thread_handle
;
44 static dissector_handle_t logcat_text_threadtime_handle
;
45 static dissector_handle_t logcat_text_long_handle
;
47 static int exported_pdu_tap
= -1;
49 static GRegex
*special_regex
;
50 static GRegex
*brief_regex
;
51 static GRegex
*tag_regex
;
52 static GRegex
*time_regex
;
53 static GRegex
*process_regex
;
54 static GRegex
*thread_regex
;
55 static GRegex
*threadtime_regex
;
56 static GRegex
*long_regex
;
58 static const char dissector_name
[] = "Logcat Text";
60 typedef int (*tGETTER
) (const char *frame
, const char *token
, tvbuff_t
*tvb
,
61 proto_tree
*maintree
, int start_offset
, packet_info
*pinfo
);
65 const tGETTER
*getters
;
66 unsigned no_of_getters
;
69 void proto_register_logcat_text(void);
70 void proto_reg_handoff_logcat_text(void);
72 static int get_priority(const char *frame
, const char *token
, tvbuff_t
*tvb
,
73 proto_tree
*maintree
, int start_offset
, packet_info
*pinfo _U_
) {
75 char *p
= g_strstr_len(frame
+ start_offset
, -1, token
);
76 int offset
= (int)(p
- frame
);
101 proto_tree_add_uint(maintree
, hf_logcat_text_priority
, tvb
, offset
, 1, prio
);
105 static int get_tag(const char *frame
, const char *token
, tvbuff_t
*tvb
,
106 proto_tree
*maintree
, int start_offset
, packet_info
*pinfo
) {
107 char *p
= g_strstr_len(frame
+ start_offset
, -1, token
);
108 int offset
= (int)(p
- frame
);
109 uint8_t *src_addr
= wmem_strdup(pinfo
->pool
, token
);
110 int tok_len
= (int)strlen(token
);
112 proto_tree_add_string(maintree
, hf_logcat_text_tag
, tvb
, offset
, tok_len
,
114 set_address(&pinfo
->src
, AT_STRINGZ
, tok_len
+ 1, src_addr
);
115 set_address(&pinfo
->dst
, AT_STRINGZ
, sizeof(dissector_name
), dissector_name
);
116 return offset
+ tok_len
;
119 static int get_ptid(const char *frame
, const char *token
, tvbuff_t
*tvb
,
120 proto_tree
*maintree
, int header_field
, int start_offset
) {
121 char *p
= g_strstr_len(frame
+ start_offset
, -1, token
);
122 int offset
= (int)(p
- frame
);
124 proto_tree_add_uint(maintree
, header_field
, tvb
, offset
, (int)strlen(token
),
125 (uint32_t)g_ascii_strtoull(token
, NULL
, 10));
126 return offset
+ (int)strlen(token
);
129 static int get_pid(const char *frame
, const char *token
, tvbuff_t
*tvb
,
130 proto_tree
*maintree
, int start_offset
, packet_info
*pinfo _U_
) {
131 return get_ptid(frame
, token
, tvb
, maintree
, hf_logcat_text_pid
, start_offset
);
134 static int get_tid(const char *frame
, const char *token
, tvbuff_t
*tvb
,
135 proto_tree
*maintree
, int start_offset
, packet_info
*pinfo _U_
) {
136 return get_ptid(frame
, token
, tvb
, maintree
, hf_logcat_text_tid
, start_offset
);
139 static int get_log(const char *frame
, const char *token
, tvbuff_t
*tvb
,
140 proto_tree
*maintree
, int start_offset
, packet_info
*pinfo
) {
141 char *p
= g_strstr_len(frame
+ start_offset
, -1, token
);
142 int offset
= (int)(p
- frame
);
144 proto_tree_add_string(maintree
, hf_logcat_text_log
, tvb
, offset
,
145 (int)strlen(token
), token
);
146 col_add_str(pinfo
->cinfo
, COL_INFO
, token
);
147 return offset
+ (int)strlen(token
);
150 static int get_time(const char *frame
, const char *token
, tvbuff_t
*tvb
,
151 proto_tree
*maintree
, int start_offset
, packet_info
*pinfo
) {
159 p
= g_strstr_len(frame
+ start_offset
, -1, token
);
160 offset
= (int)(p
- frame
);
162 if (6 == sscanf(token
, "%d-%d %d:%d:%d.%d", &date
.tm_mon
, &date
.tm_mday
,
163 &date
.tm_hour
, &date
.tm_min
, &date
.tm_sec
, &ms
)) {
167 seconds
= mktime(&date
);
169 ts
.nsecs
= (int) (ms
* 1e6
);
170 proto_tree_add_time(maintree
, hf_logcat_text_timestamp
, tvb
, offset
,
171 (int)strlen(token
), &ts
);
173 proto_tree_add_expert(maintree
, pinfo
, &ei_malformed_time
, tvb
, offset
, -1);
175 return offset
+ (int)strlen(token
);
178 static int dissect_logcat_text(tvbuff_t
*tvb
, proto_tree
*tree
, packet_info
*pinfo
,
179 const dissect_info_t
*dinfo
) {
182 char *frame
= tvb_get_string_enc(pinfo
->pool
, tvb
, 0, tvb_captured_length(tvb
),
184 proto_item
*mainitem
= proto_tree_add_item(tree
, proto_logcat_text
, tvb
, 0, -1, ENC_NA
);
185 proto_tree
*maintree
= proto_item_add_subtree(mainitem
, ett_logcat
);
188 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, dissector_name
);
190 if (!g_regex_match(special_regex
, frame
, G_REGEX_MATCH_NOTEMPTY
, NULL
)) {
192 tokens
= g_regex_split(*dinfo
->regex
, frame
, G_REGEX_MATCH_NOTEMPTY
);
193 if (NULL
== tokens
) return 0;
194 if (g_strv_length(tokens
) != dinfo
->no_of_getters
+ 2) {
195 proto_tree_add_expert(maintree
, pinfo
, &ei_malformed_token
, tvb
, offset
, -1);
200 for (i
= 0; i
< dinfo
->no_of_getters
; ++i
) {
201 offset
= ((*dinfo
->getters
[i
])(frame
, tokens
[i
+ 1], tvb
, maintree
, offset
, pinfo
));
204 tokens
= g_regex_split(special_regex
, frame
, G_REGEX_MATCH_NOTEMPTY
);
205 if (NULL
== tokens
) return 0;
206 offset
= get_log(frame
, tokens
[1], tvb
, maintree
, 0, pinfo
);
212 static void add_exported_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, const char * subdissector_name
){
213 if (have_tap_listener(exported_pdu_tap
)) {
214 exp_pdu_data_t
*exp_pdu_data
;
216 exp_pdu_data
= export_pdu_create_tags(pinfo
, subdissector_name
, EXP_PDU_TAG_DISSECTOR_NAME
, NULL
);
218 exp_pdu_data
->tvb_captured_length
= tvb_captured_length(tvb
);
219 exp_pdu_data
->tvb_reported_length
= tvb_reported_length(tvb
);
220 exp_pdu_data
->pdu_tvb
= tvb
;
221 tap_queue_packet(exported_pdu_tap
, pinfo
, exp_pdu_data
);
225 static int dissect_logcat_text_brief(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
227 static const tGETTER getters
[] = { get_priority
, get_tag
, get_pid
, get_log
};
228 dissect_info_t dinfo
= { &brief_regex
, getters
, array_length(getters
) };
230 add_exported_pdu(tvb
,pinfo
,"logcat_text_brief");
231 return dissect_logcat_text(tvb
, tree
, pinfo
, &dinfo
);
234 static int dissect_logcat_text_tag(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
236 static const tGETTER getters
[] = { get_priority
, get_tag
, get_log
};
237 dissect_info_t dinfo
= { &tag_regex
, getters
, array_length(getters
) };
239 add_exported_pdu(tvb
,pinfo
,"logcat_text_tag");
240 return dissect_logcat_text(tvb
, tree
, pinfo
, &dinfo
);
243 static int dissect_logcat_text_process(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
245 static const tGETTER getters
[] = { get_priority
, get_pid
, get_log
};
246 dissect_info_t dinfo
= { &process_regex
, getters
, array_length(getters
) };
248 add_exported_pdu(tvb
,pinfo
,"logcat_text_process");
249 set_address(&pinfo
->dst
, AT_STRINGZ
, 1, "");
250 set_address(&pinfo
->src
, AT_STRINGZ
, 1, "");
252 return dissect_logcat_text(tvb
, tree
, pinfo
, &dinfo
);
255 static int dissect_logcat_text_time(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
257 static const tGETTER getters
[] = { get_time
, get_priority
, get_tag
, get_pid
, get_log
};
258 dissect_info_t dinfo
= { &time_regex
, getters
, array_length(getters
) };
260 add_exported_pdu(tvb
,pinfo
,"logcat_text_time");
261 return dissect_logcat_text(tvb
, tree
, pinfo
, &dinfo
);
264 static int dissect_logcat_text_thread(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
266 static const tGETTER getters
[] = { get_priority
, get_pid
, get_tid
, get_log
};
267 dissect_info_t dinfo
= { &thread_regex
, getters
, array_length(getters
) };
269 add_exported_pdu(tvb
,pinfo
,"logcat_text_brief");
270 set_address(&pinfo
->dst
, AT_STRINGZ
, 1, "");
271 set_address(&pinfo
->src
, AT_STRINGZ
, 1, "");
273 return dissect_logcat_text(tvb
, tree
, pinfo
, &dinfo
);
276 static int dissect_logcat_text_threadtime(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
278 static const tGETTER getters
[] = { get_time
, get_pid
, get_tid
, get_priority
, get_tag
, get_log
};
279 dissect_info_t dinfo
= { &threadtime_regex
, getters
, array_length(getters
) };
281 add_exported_pdu(tvb
,pinfo
,"logcat_text_threadtime");
282 return dissect_logcat_text(tvb
, tree
, pinfo
, &dinfo
);
285 static int dissect_logcat_text_long(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
287 static const tGETTER getters
[] = { get_time
, get_pid
, get_tid
, get_priority
, get_tag
, get_log
};
288 dissect_info_t dinfo
= { &long_regex
, getters
, array_length(getters
) };
290 add_exported_pdu(tvb
,pinfo
,"logcat_text_long");
291 return dissect_logcat_text(tvb
, tree
, pinfo
, &dinfo
);
294 static void logcat_text_init(void)
296 special_regex
= g_regex_new(SPECIAL_STRING
, (GRegexCompileFlags
)(G_REGEX_ANCHORED
| G_REGEX_OPTIMIZE
| G_REGEX_RAW
), G_REGEX_MATCH_NOTEMPTY
, NULL
);
297 brief_regex
= g_regex_new(BRIEF_STRING
, (GRegexCompileFlags
)(G_REGEX_ANCHORED
| G_REGEX_OPTIMIZE
| G_REGEX_RAW
), G_REGEX_MATCH_NOTEMPTY
, NULL
);
298 tag_regex
= g_regex_new(TAG_STRING
, (GRegexCompileFlags
)(G_REGEX_ANCHORED
| G_REGEX_OPTIMIZE
| G_REGEX_RAW
), G_REGEX_MATCH_NOTEMPTY
, NULL
);
299 time_regex
= g_regex_new(TIME_STRING
, (GRegexCompileFlags
)(G_REGEX_ANCHORED
| G_REGEX_OPTIMIZE
| G_REGEX_RAW
), G_REGEX_MATCH_NOTEMPTY
, NULL
);
300 thread_regex
= g_regex_new(THREAD_STRING
, (GRegexCompileFlags
)(G_REGEX_ANCHORED
| G_REGEX_OPTIMIZE
| G_REGEX_RAW
), G_REGEX_MATCH_NOTEMPTY
, NULL
);
301 threadtime_regex
= g_regex_new(THREADTIME_STRING
, (GRegexCompileFlags
)(G_REGEX_ANCHORED
| G_REGEX_OPTIMIZE
| G_REGEX_RAW
), G_REGEX_MATCH_NOTEMPTY
, NULL
);
302 process_regex
= g_regex_new(PROCESS_STRING
, (GRegexCompileFlags
)(G_REGEX_ANCHORED
| G_REGEX_OPTIMIZE
| G_REGEX_RAW
), G_REGEX_MATCH_NOTEMPTY
, NULL
);
303 long_regex
= g_regex_new(LONG_STRING
, (GRegexCompileFlags
)(G_REGEX_MULTILINE
| G_REGEX_OPTIMIZE
| G_REGEX_RAW
), G_REGEX_MATCH_NOTEMPTY
, NULL
);
306 static void logcat_text_cleanup(void)
308 g_regex_unref(special_regex
);
309 g_regex_unref(brief_regex
);
310 g_regex_unref(tag_regex
);
311 g_regex_unref(time_regex
);
312 g_regex_unref(thread_regex
);
313 g_regex_unref(threadtime_regex
);
314 g_regex_unref(process_regex
);
315 g_regex_unref(long_regex
);
318 void proto_register_logcat_text(void) {
319 expert_module_t
*expert_module
;
320 static hf_register_info hf
[] = {
321 { &hf_logcat_text_timestamp
,
322 { "Timestamp", "logcat_text.timestamp",
323 FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x00, NULL
, HFILL
326 { &hf_logcat_text_tag
,
327 { "Tag", "logcat_text.tag",
328 FT_STRING
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
331 { &hf_logcat_text_log
,
332 { "Log", "logcat_text.log",
333 FT_STRING
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
336 { &hf_logcat_text_priority
,
337 { "Priority", "logcat_text.priority",
338 FT_UINT8
, BASE_DEC
, VALS(priority_vals
), 0x00, NULL
, HFILL
341 { &hf_logcat_text_pid
,
342 { "PID", "logcat_text.pid",
343 FT_UINT32
, BASE_DEC
, NULL
, 0x00, "Process ID", HFILL
346 { &hf_logcat_text_tid
,
347 { "TID", "logcat_text.tid",
348 FT_UINT32
, BASE_DEC
, NULL
, 0x00, "Thread ID", HFILL
353 static ei_register_info ei
[] = {
354 { &ei_malformed_time
, { "logcat_text.malformed_time", PI_PROTOCOL
, PI_ERROR
, "Malformed time data", EXPFILL
}},
355 { &ei_malformed_token
, { "logcat_text.malformed_token", PI_PROTOCOL
, PI_ERROR
, "Failed to decode one or more tokens", EXPFILL
}},
358 static int *ett
[] = { &ett_logcat
};
360 proto_logcat_text
= proto_register_protocol("Android Logcat Text", dissector_name
,
362 proto_register_field_array(proto_logcat_text
, hf
, array_length(hf
));
363 proto_register_subtree_array(ett
, array_length(ett
));
365 logcat_text_brief_handle
= register_dissector("logcat_text_brief",
366 dissect_logcat_text_brief
, proto_logcat_text
);
367 logcat_text_tag_handle
= register_dissector("logcat_text_tag",
368 dissect_logcat_text_tag
, proto_logcat_text
);
369 logcat_text_time_handle
= register_dissector("logcat_text_time",
370 dissect_logcat_text_time
, proto_logcat_text
);
371 logcat_text_process_handle
= register_dissector("logcat_text_process",
372 dissect_logcat_text_process
, proto_logcat_text
);
373 logcat_text_thread_handle
= register_dissector("logcat_text_thread",
374 dissect_logcat_text_thread
, proto_logcat_text
);
375 logcat_text_threadtime_handle
= register_dissector("logcat_text_threadtime",
376 dissect_logcat_text_threadtime
, proto_logcat_text
);
377 logcat_text_long_handle
= register_dissector("logcat_text_long",
378 dissect_logcat_text_long
, proto_logcat_text
);
380 register_init_routine(logcat_text_init
);
381 register_cleanup_routine(logcat_text_cleanup
);
383 expert_module
= expert_register_protocol(proto_logcat_text
);
384 expert_register_field_array(expert_module
, ei
, array_length(ei
));
386 exported_pdu_tap
= register_export_pdu_tap("Logcat Text");
389 void proto_reg_handoff_logcat_text(void) {
390 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_BRIEF
,
391 logcat_text_brief_handle
);
392 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_TAG
,
393 logcat_text_tag_handle
);
394 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_TIME
,
395 logcat_text_time_handle
);
396 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_THREAD
,
397 logcat_text_thread_handle
);
398 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_THREADTIME
,
399 logcat_text_threadtime_handle
);
400 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_PROCESS
,
401 logcat_text_process_handle
);
402 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_LONG
,
403 logcat_text_long_handle
);
407 * Editor modelines - https://www.wireshark.org/tools/modelines.html
412 * indent-tabs-mode: nil
415 * vi: set shiftwidth=4 tabstop=8 expandtab:
416 * :indentSize=4:tabSize=8:noTabs=true: