aboutsummaryrefslogtreecommitdiff
path: root/util/cbfstool/elogtool.c
diff options
context:
space:
mode:
authorRicardo Quesada <ricardoq@google.com>2021-07-16 16:49:04 -0700
committerPaul Fagerburg <pfagerburg@chromium.org>2021-08-05 22:00:35 +0000
commitc2cf3946c95cca7a84b87725b453fdf2b8932ffd (patch)
tree0600ce9b494b28bafcb56d8ffc171443e7c648f3 /util/cbfstool/elogtool.c
parentcb4bb393b52d8feb0979afd972c2fb0c6e41d9eb (diff)
util/elogtool: add tool to print elog events
Add a new tool that that prints elog events. The tool, as input, accepts either a file with the RW_ELOG contents, or if the file is not provided it reads the contents of RW_ELOG by calling the "flashrom" tool. The tool is based on "mosys eventlog list"[1]. For the moment it only supports "list", but future commits will add additional functionality. This commit also adds missing ELOG defines needed for the tool. These defines are added with the rest of the ELOG defines, in include/commonlib/bsd/elog.h The tool is placed inside util/cbfstool. The rationale behind the decision, is that this tool shares a lot in common with the other tools located in cbfstool: vboot dependency, shared files like common.o and valstr.o, and in spirit is similar to some of the tools located in cbfstool/. As an example, you call the tool like the following: $ elogtool list -f rw_elog_dump.bin [1]: https://chromium.googlesource.com/chromiumos/platform/mosys/+/refs/heads/main/lib/eventlog/elog.c BUG=b:172210863 Signed-off-by: Ricardo Quesada <ricardoq@google.com> Change-Id: Ia1fe1c9ed3c4c6bda846055d4b10943b54463935 Reviewed-on: https://review.coreboot.org/c/coreboot/+/56406 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org> Reviewed-by: Jack Rosenthal <jrosenth@chromium.org>
Diffstat (limited to 'util/cbfstool/elogtool.c')
-rw-r--r--util/cbfstool/elogtool.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/util/cbfstool/elogtool.c b/util/cbfstool/elogtool.c
new file mode 100644
index 0000000000..ba59eac514
--- /dev/null
+++ b/util/cbfstool/elogtool.c
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+#include <getopt.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <common.h>
+#include <commonlib/bsd/elog.h>
+#include <flashrom.h>
+
+#include "eventlog.h"
+
+enum elogtool_return {
+ ELOGTOOL_EXIT_SUCCESS = 0,
+ ELOGTOOL_EXIT_BAD_ARGS,
+ ELOGTOOL_EXIT_BAD_INPUT_PATH,
+ ELOGTOOL_EXIT_NOT_ENOUGH_MEMORY,
+ ELOGTOOL_EXIT_INVALID_ELOG_FORMAT,
+};
+
+static struct option long_options[] = {
+ {"file", required_argument, 0, 'f'},
+ {"help", no_argument, 0, 'h'},
+ {NULL, 0, 0, 0},
+};
+
+static void usage(char *invoked_as)
+{
+ fprintf(stderr, "elogtool: list elog events\n\n"
+ "USAGE:\n"
+ "\t%s COMMAND [-f <filename>]\n\n"
+ "where, COMMAND is:\n"
+ " list = lists all the event logs in human readable format\n\n"
+ "ARGS\n"
+ "-f, --file <filename> Input file that holds event log partition.\n"
+ " If empty it will try to read from the RW_ELOG ROM region\n"
+ "-h, --help Print this help\n",
+ invoked_as);
+}
+
+// If filename is empty, read RW_ELOG from flashrom. Otherwise read the RW_ELOG from a file.
+// Buffer must be freed by caller.
+static int elog_read(const char *filename, struct buffer *buffer)
+{
+ if (filename == NULL) {
+ uint8_t *buf;
+ uint32_t buf_size;
+
+ if (flashrom_read(FLASHROM_PROGRAMMER_INTERNAL_AP, "RW_ELOG", &buf, &buf_size)
+ != VB2_SUCCESS) {
+ fprintf(stderr, "Could not read RW_ELOG region using flashrom\n");
+ return ELOGTOOL_EXIT_BAD_INPUT_PATH;
+ }
+ buffer_init(buffer, NULL, buf, buf_size);
+ } else {
+ if (buffer_from_file(buffer, filename) != 0) {
+ fprintf(stderr, "Could not read input file: %s\n", filename);
+ return ELOGTOOL_EXIT_BAD_INPUT_PATH;
+ }
+ }
+
+ return 0;
+}
+
+static int elog_list_events(const struct buffer *buf)
+{
+ const struct event_header *event;
+ const void *data;
+ uint32_t data_len;
+ unsigned int count = 0;
+
+ data = buffer_get(buf);
+ data_len = buffer_size(buf);
+
+ if (elog_verify_header(data) != CB_SUCCESS) {
+ fprintf(stderr, "FATAL: Invalid elog header\n");
+ return ELOGTOOL_EXIT_INVALID_ELOG_FORMAT;
+ }
+
+ /* Point to first event */
+ event = (const struct event_header *)(data + sizeof(struct elog_header));
+
+ while ((const void *)(event) < data + data_len) {
+ if (event->type == ELOG_TYPE_EOL || event->length == 0)
+ break;
+
+ eventlog_print_event(event, count);
+ event = elog_get_next_event(event);
+ count++;
+ }
+
+ return ELOGTOOL_EXIT_SUCCESS;
+}
+
+static int cmd_list(const char *filename)
+{
+ int ret;
+
+ // Returned buffer must be freed.
+ struct buffer buf;
+ ret = elog_read(filename, &buf);
+ if (ret != 0)
+ return ret;
+
+ ret = elog_list_events(&buf);
+
+ buffer_delete(&buf);
+ return ret;
+}
+
+
+int main(int argc, char **argv)
+{
+ int argflag;
+ char *input_file = NULL;
+
+ if (argc < 2) {
+ usage(argv[0]);
+ return ELOGTOOL_EXIT_BAD_ARGS;
+ }
+
+ while (1) {
+ int option_index;
+ argflag = getopt_long(argc, argv, "hf:", long_options, &option_index);
+ if (argflag == -1)
+ break;
+
+ switch (argflag) {
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ return ELOGTOOL_EXIT_SUCCESS;
+
+ case 'f':
+ if (!optarg) {
+ usage(argv[0]);
+ return ELOGTOOL_EXIT_BAD_ARGS;
+ }
+
+ input_file = optarg;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* At least one command must be available. */
+ if (optind >= argc) {
+ usage(argv[0]);
+ return ELOGTOOL_EXIT_BAD_ARGS;
+ }
+
+ if (!strcmp(argv[optind], "list"))
+ return cmd_list(input_file);
+
+ return ELOGTOOL_EXIT_SUCCESS;
+}