diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/sieve-binary-debug.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/sieve-binary-debug.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/sieve-binary-debug.c b/pigeonhole/src/lib-sieve/sieve-binary-debug.c new file mode 100644 index 0000000..5e8b13a --- /dev/null +++ b/pigeonhole/src/lib-sieve/sieve-binary-debug.c @@ -0,0 +1,276 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" + +#include "sieve-common.h" +#include "sieve-error.h" +#include "sieve-code.h" + +#include "sieve-binary-private.h" + +/* Quick 'n dirty debug */ +#if 0 +#define debug_printf(...) printf ("lineinfo: " __VA_ARGS__) +#else +#define debug_printf(...) +#endif + +/* + * Opcodes + */ + +enum { + LINPROG_OP_COPY, + LINPROG_OP_ADVANCE_PC, + LINPROG_OP_ADVANCE_LINE, + LINPROG_OP_SET_COLUMN, + LINPROG_OP_SPECIAL_BASE +}; + +#define LINPROG_LINE_BASE 0 +#define LINPROG_LINE_RANGE 4 + +/* + * Lineinfo writer + */ + +struct sieve_binary_debug_writer { + struct sieve_binary_block *sblock; + + sieve_size_t address; + unsigned int line; + unsigned int column; +}; + +struct sieve_binary_debug_writer * +sieve_binary_debug_writer_init(struct sieve_binary_block *sblock) +{ + struct sieve_binary_debug_writer *dwriter; + + dwriter = i_new(struct sieve_binary_debug_writer, 1); + dwriter->sblock = sblock; + + return dwriter; +} + +void sieve_binary_debug_writer_deinit( + struct sieve_binary_debug_writer **dwriter) +{ + i_free(*dwriter); + *dwriter = NULL; +} + +void sieve_binary_debug_emit(struct sieve_binary_debug_writer *dwriter, + sieve_size_t code_address, unsigned int code_line, + unsigned int code_column) +{ + i_assert(code_address >= dwriter->address); + + struct sieve_binary_block *sblock = dwriter->sblock; + sieve_size_t address_inc = code_address - dwriter->address; + int line_inc = (code_line > dwriter->line ? + (int)(code_line - dwriter->line) : + -(int)(dwriter->line - code_line)); + unsigned int sp_opcode = 0; + + /* Check for applicability of special opcode */ + if (line_inc > 0 && + (LINPROG_LINE_BASE + LINPROG_LINE_RANGE - 1) >= line_inc) { + sp_opcode = LINPROG_OP_SPECIAL_BASE + + (line_inc - LINPROG_LINE_BASE) + + (LINPROG_LINE_RANGE * address_inc); + + if (sp_opcode > 255) + sp_opcode = 0; + } + + /* Update line and address */ + if (sp_opcode == 0) { + if (line_inc != 0) { + (void)sieve_binary_emit_byte(sblock, + LINPROG_OP_ADVANCE_LINE); + (void)sieve_binary_emit_unsigned( + sblock, (unsigned int)line_inc); + } + + if (address_inc > 0) { + (void)sieve_binary_emit_byte(sblock, + LINPROG_OP_ADVANCE_PC); + (void)sieve_binary_emit_unsigned(sblock, address_inc); + } + } else { + (void)sieve_binary_emit_byte(sblock, sp_opcode); + } + + /* Set column */ + if (dwriter->column != code_column) { + (void)sieve_binary_emit_byte(sblock, LINPROG_OP_SET_COLUMN); + (void)sieve_binary_emit_unsigned(sblock, code_column); + } + + /* Generate matrix row */ + (void)sieve_binary_emit_byte(sblock, LINPROG_OP_COPY); + + dwriter->address = code_address; + dwriter->line = code_line; + dwriter->column = code_column; +} + +/* + * Debug reader + */ + +struct sieve_binary_debug_reader { + struct sieve_binary_block *sblock; + + sieve_size_t address, last_address; + unsigned int line, last_line; + + unsigned int column; + + sieve_size_t state; +}; + +struct sieve_binary_debug_reader * +sieve_binary_debug_reader_init(struct sieve_binary_block *sblock) +{ + struct sieve_binary_debug_reader *dreader; + + dreader = i_new(struct sieve_binary_debug_reader, 1); + dreader->sblock = sblock; + + return dreader; +} + +void sieve_binary_debug_reader_deinit( + struct sieve_binary_debug_reader **dreader) +{ + i_free(*dreader); + *dreader = NULL; +} + +void sieve_binary_debug_reader_reset(struct sieve_binary_debug_reader *dreader) +{ + dreader->address = 0; + dreader->line = 0; + dreader->column = 0; + dreader->state = 0; +} + +unsigned int +sieve_binary_debug_read_line(struct sieve_binary_debug_reader *dreader, + sieve_size_t code_address) +{ + size_t linprog_size; + sieve_size_t address; + unsigned int line; + + if (code_address < dreader->last_address) + sieve_binary_debug_reader_reset(dreader); + + if (code_address >= dreader->last_address && + code_address < dreader->address) { + debug_printf("%08llx: NOOP [%08llx]\n", + (unsigned long long)dreader->state, + (unsigned long long)code_address); + return dreader->last_line; + } + + address = dreader->address; + line = dreader->line; + + debug_printf("%08llx: READ [%08llx]\n", + (unsigned long long)dreader->state, + (unsigned long long)code_address); + + linprog_size = sieve_binary_block_get_size(dreader->sblock); + while (dreader->state < linprog_size) { + unsigned int opcode; + unsigned int value; + int line_inc; + + if (sieve_binary_read_byte(dreader->sblock, + &dreader->state, &opcode)) { + switch (opcode) { + case LINPROG_OP_COPY: + debug_printf("%08llx: COPY ==> %08llx: %ld\n", + (unsigned long long)dreader->state, + (unsigned long long)address, line); + + dreader->last_address = dreader->address; + dreader->last_line = dreader->line; + + dreader->address = address; + dreader->line = line; + + if (code_address < address) + return dreader->last_line; + else if (code_address == address) + return dreader->line; + break; + case LINPROG_OP_ADVANCE_PC: + debug_printf("%08llx: ADV_PC\n", + (unsigned long long)dreader->state); + if (!sieve_binary_read_unsigned( + dreader->sblock, &dreader->state, + &value)) { + sieve_binary_debug_reader_reset(dreader); + return 0; + } + debug_printf(" : + %d\n", value); + address += value; + break; + case LINPROG_OP_ADVANCE_LINE: + debug_printf("%08llx: ADV_LINE\n", + (unsigned long long)dreader->state); + if (!sieve_binary_read_unsigned( + dreader->sblock, &dreader->state, + &value)) { + sieve_binary_debug_reader_reset(dreader); + return 0; + } + line_inc = (int)value; + debug_printf(" : + %d\n", line_inc); + line = (line_inc > 0 ? + line + (unsigned int)line_inc : + line - (unsigned int)-line_inc); + break; + case LINPROG_OP_SET_COLUMN: + debug_printf("%08llx: SET_COL\n", + (unsigned long long)dreader->state); + if (!sieve_binary_read_unsigned( + dreader->sblock, &dreader->state, + &value)) { + sieve_binary_debug_reader_reset(dreader); + return 0; + } + debug_printf(" : = %d\n", value); + dreader->column = value; + break; + default: + opcode -= LINPROG_OP_SPECIAL_BASE; + + address += (opcode / LINPROG_LINE_RANGE); + line += LINPROG_LINE_BASE + + (opcode % LINPROG_LINE_RANGE); + + debug_printf("%08llx: SPECIAL\n", + (unsigned long long)dreader->state); + debug_printf(" : +A %d +L %d\n", + (opcode / LINPROG_LINE_RANGE), + LINPROG_LINE_BASE + + (opcode % LINPROG_LINE_RANGE)); + break; + } + } else { + debug_printf("OPCODE READ FAILED\n"); + sieve_binary_debug_reader_reset(dreader); + return 0; + } + } + + return dreader->line; +} + |