The module list may be split into multiple lines, at arbitrary
position. The parsing function now tries to handle that, though not in
a very robust way, by means of heuristic that decides whether the next
line is a continuation of the previous.
Closes #24.
Signed-off-by: Martin Milata <mmilata(a)redhat.com>
---
lib/koops_stacktrace.c | 85 +++++++++++++++++++++++++++++++++++++++--------
tests/koops_stacktrace.at | 63 +++++++++++++++++++++++++++++++++--
tests/python/koops.py | 2 +-
3 files changed, 134 insertions(+), 16 deletions(-)
diff --git a/lib/koops_stacktrace.c b/lib/koops_stacktrace.c
index a10d816..8964d04 100644
--- a/lib/koops_stacktrace.c
+++ b/lib/koops_stacktrace.c
@@ -144,6 +144,34 @@ sr_koops_stacktrace_parse(const char **input,
return stacktrace;
}
+static bool
+module_list_continues(const char *input)
+{
+ char *end = strchr(input, '\n');
+
+ /* Module list shouldn't be on the last line */
+ if (!end || input == end)
+ return false;
+
+ size_t line_len = end - input;
+ char *line = sr_malloc(line_len + 1);
+ memcpy(line, input, line_len);
+ line[line_len] = '\0';
+
+ bool res = true;
+
+ /* Usually follows the module list */
+ if (strstr(line, "Pid: "))
+ res = false;
+ /* There should be no timestamp in the continuation */
+ else if (sr_koops_skip_timestamp(&input))
+ res = false;
+ /* Other conditions may need to be added */
+
+ free(line);
+ return res;
+}
+
char **
sr_koops_stacktrace_parse_modules(const char **input)
{
@@ -157,27 +185,58 @@ sr_koops_stacktrace_parse_modules(const char **input)
if (!sr_skip_string(&local_input, "Modules linked in:"))
return NULL;
- sr_skip_char_span(&local_input, " \t");
+ int ws = sr_skip_char_span(&local_input, " \t");
int result_size = 20, result_offset = 0;
char **result = sr_malloc(result_size * sizeof(char*));
char *module;
- bool success;
- while ((success = sr_parse_char_cspan(&local_input, " \t\n[",
&module)))
+ while (true)
{
- // result_size is lowered by 1 because we need to terminate
- // the list by a NULL pointer.
- if (result_offset == result_size - 1)
+ if (sr_parse_char_cspan(&local_input, " \t\n[", &module))
{
- result_size *= 2;
- result = sr_realloc(result,
- result_size * sizeof(char*));
+ // result_size is lowered by 1 because we need to terminate
+ // the list by a NULL pointer.
+ if (result_offset == result_size - 1)
+ {
+ result_size *= 2;
+ result = sr_realloc(result,
+ result_size * sizeof(char*));
+ }
+
+ result[result_offset] = module;
+ ++result_offset;
+ ws = sr_skip_char_span(&local_input, " \t");
}
-
- result[result_offset] = module;
- ++result_offset;
- sr_skip_char_span(&local_input, " \t");
+ else if(*local_input == '\n')
+ {
+ /* We're at the end of the line. Check whether the next line might
+ * be a continuation of the module list. */
+ if (!module_list_continues(local_input + 1))
+ break;
+
+ local_input++;
+
+ /* If the next line does not start with space and there wasn't
+ * any space before the newline either, then the last module was
+ * split into two parts and we need to read the rest */
+ if (*local_input != ' ' && ws == 0 && result_offset
> 0)
+ {
+ char *therest;
+ if (!sr_parse_char_cspan(&local_input, " \t\n[",
&therest))
+ {
+ break; /* wtf? */
+ }
+
+ char *tmp = sr_asprintf("%s%s", result[result_offset-1],
therest);
+ free(result[result_offset-1]);
+ result[result_offset-1] = tmp;
+ }
+
+ ws = sr_skip_char_span(&local_input, " \t");
+ }
+ else
+ break;
}
result[result_offset] = NULL;
diff --git a/tests/koops_stacktrace.at b/tests/koops_stacktrace.at
index d30e8b9..672b0fc 100644
--- a/tests/koops_stacktrace.at
+++ b/tests/koops_stacktrace.at
@@ -22,7 +22,6 @@ check(bool success,
if (modules)
{
- assert(*input == '\0');
int offset = 0;
while (modules[offset])
{
@@ -55,6 +54,38 @@ main(void)
check(true,
"[110417.280431] Modules linked in: vfat fat usb_storage",
modules);
+
+ check(true,
+ "[110417.280431] Modules linked in: vfat fat usb_storage [last unloaded:
scsi_wait_scan]\n",
+ modules);
+
+ check(true,
+ "[110417.280431] Modules linked in: vfat fat usb_storage \n[last unloaded:
scsi_wait_scan]\n",
+ modules);
+
+ check(true,
+ "[110417.280431] Modules linked in: vfat fat usb_storage\n [last unloaded:
scsi_wait_scan]\n",
+ modules);
+
+ check(true,
+ "[110417.280431] Modules linked in: vfat fat usb_st\norage [last unloaded:
scsi_wait_scan]\n",
+ modules);
+
+ check(true,
+ "[110417.280431] Modules linked in: vfat fat \nusb_storage [last unloaded:
scsi_wait_scan]\n",
+ modules);
+
+ check(true,
+ "[110417.280431] Modules linked in: vfat fat\n usb_storage [last unloaded:
scsi_wait_scan]\n",
+ modules);
+
+ check(true,
+ "[110417.280431] Modules linked in: vfat fat usb_storage\n"
+ "Pid: 31337, comm: ksoftirqd/2\n",
+ modules);
+
+ check(false, "[110417.280434] I hate autotest", modules);
+
return 0;
}
]])
@@ -299,7 +330,35 @@ main(void)
" , \"bluetooth\"\n"
" , \"iwlwifi\"\n"
" , \"snd_pcm\"\n"
- " , \"parport_pc\" ]\n"
+ " , \"parport_pc\"\n"
+ " , \"joydev\"\n"
+ " , \"parport\"\n"
+ " , \"snd_timer\"\n"
+ " , \"microcode\"\n"
+ " , \"mac80211\"\n"
+ " , \"snd\"\n"
+ " , \"soundcore\"\n"
+ " , \"snd_page_alloc\"\n"
+ " , \"i2c_i801\"\n"
+ " , \"cfg80211\"\n"
+ " , \"iTCO_wdt\"\n"
+ " , \"iTCO_vendor_support\"\n"
+ " , \"rfkill\"\n"
+ " , \"e1000e\"\n"
+ " , \"sunrpc\"\n"
+ " , \"xts\"\n"
+ " , \"gf128mul\"\n"
+ " , \"dm_crypt\"\n"
+ " , \"sdhci_pci\"\n"
+ " , \"sdhci\"\n"
+ " , \"mmc_core\"\n"
+ " , \"wmi\"\n"
+ " , \"i915\"\n"
+ " , \"drm_kms_helper\"\n"
+ " , \"drm\"\n"
+ " , \"i2c_algo_bit\"\n"
+ " , \"i2c_core\"\n"
+ " , \"video\" ]\n"
", \"frames\":\n"
" [ { \"address\": 18446744071579204319\n"
" , \"reliable\": true\n"
diff --git a/tests/python/koops.py b/tests/python/koops.py
index b702548..b343979 100755
--- a/tests/python/koops.py
+++ b/tests/python/koops.py
@@ -11,7 +11,7 @@ except ImportError:
path = '../kerneloopses/rhbz-827868'
frames_expected = 32
-mods_expected = 91
+mods_expected = 119
if not os.path.isfile(path):
path = '../' + path
--
1.7.11.7