summaryrefslogtreecommitdiffstats
path: root/src/Backtrace/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Backtrace/main.c')
-rw-r--r--src/Backtrace/main.c74
1 files changed, 65 insertions, 9 deletions
diff --git a/src/Backtrace/main.c b/src/Backtrace/main.c
index 459185e..315b6ef 100644
--- a/src/Backtrace/main.c
+++ b/src/Backtrace/main.c
@@ -20,10 +20,14 @@
#include <argp.h>
#include <stdlib.h>
#include <sysexits.h>
+#include <string.h>
#include "config.h"
#include "backtrace.h"
#include "fallback.h"
+/* Too large files are trimmed. */
+#define FILE_SIZE_LIMIT 20000000 /* ~ 20 MB */
+
#define EX_PARSINGFAILED EX__MAX + 1
#define EX_THREADDETECTIONFAILED EX__MAX + 2
@@ -125,7 +129,7 @@ int main(int argc, char **argv)
arguments.filename = 0;
argp_parse(&argp, argc, argv, 0, 0, &arguments);
- /* Open input file and parse it. */
+ /* Open input file, and parse it. */
FILE *fp = fopen(arguments.filename, "r");
if (!fp)
{
@@ -133,33 +137,85 @@ int main(int argc, char **argv)
exit(EX_NOINPUT); /* No such file or directory */
}
+ /* Header and footer of the backtrace is stripped to simplify the parser.
+ * A drawback is that the backtrace must be loaded to memory.
+ */
+ fseek(fp, 0, SEEK_END);
+ size_t size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ if (size > FILE_SIZE_LIMIT)
+ {
+ fprintf(stderr, "Input file too big (%zd). Maximum size is %zd",
+ size, FILE_SIZE_LIMIT);
+ exit(EX_IOERR);
+ }
+
+ char *bttext = malloc(size + 1);
+ if (1 != fread(bttext, size, 1, fp))
+ {
+ fprintf(stderr, "Unable to read from '%s'.\n", arguments.filename);
+ exit(EX_IOERR); /* IO Error */
+ }
+
+ bttext[size] = '\0';
+ fclose(fp);
+
/* Print independent backtrace and exit. */
if (arguments.independent)
{
- struct strbuf *ibt = independent_backtrace(fp);
- fclose(fp);
+ struct strbuf *ibt = independent_backtrace(bttext);
puts(ibt->buf);
strbuf_free(ibt);
+ free(bttext);
return 0; /* OK */
}
+ /* Skip the backtrace header information. */
+ char *btnoheader_a = strstr(bttext, "\nThread ");
+ char *btnoheader_b = strstr(bttext, "#");
+ char *btnoheader = bttext;
+ if (btnoheader < btnoheader_a)
+ btnoheader = btnoheader_a + 1;
+ if (btnoheader < btnoheader_b)
+ btnoheader = btnoheader_b;
+
+ /* Cut the backtrace footer.
+ * Footer: lines not starting with # or "Thread", and separated from
+ * the backtrace body by a newline.
+ */
+ int i;
+ for (i = size - 1; i > 0; --i)
+ {
+ if (bttext[i] != '\n')
+ continue;
+ if (strncmp(bttext + i + 1, "Thread", strlen("Thread")) == 0)
+ break;
+ if (bttext[i + 1] == '#')
+ break;
+ if (bttext[i - 1] == '\n')
+ {
+ bttext[i] = '\0';
+ break;
+ }
+ }
+
/* Try to parse the backtrace. */
struct backtrace *backtrace;
- backtrace = do_parse(fp, arguments.debug_parser, arguments.debug_scanner);
+ backtrace = do_parse(btnoheader, arguments.debug_parser, arguments.debug_scanner);
/* If the parser failed print independent backtrace. */
if (!backtrace)
{
- fseek(fp, 0, SEEK_SET);
- struct strbuf *ibt = independent_backtrace(fp);
- fclose(fp);
+ struct strbuf *ibt = independent_backtrace(bttext);
puts(ibt->buf);
strbuf_free(ibt);
- /* PARSING FAILED, BUT OUTPUT CAN BE USED */
+ free(bttext);
+ /* Parsing failed, but the output can be used. */
return EX_PARSINGFAILED;
}
- fclose(fp);
+ free(bttext);
/* If a single thread is requested, remove all other threads. */
int retval = 0;