sieve-binary-debug.c [plain text]
#include "lib.h"
#include "str.h"
#include "sieve-common.h"
#include "sieve-error.h"
#include "sieve-code.h"
#include "sieve-binary-private.h"
#if 0
#define debug_printf(...) printf ("lineinfo: " __VA_ARGS__)
#else
#define debug_printf(...)
#endif
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
struct sieve_binary_debug_writer {
struct sieve_binary_block *sblock;
sieve_size_t address;
unsigned long int line;
unsigned long 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)
{
struct sieve_binary_block *sblock = dwriter->sblock;
sieve_size_t address_inc = code_address - dwriter->address;
unsigned int line_inc = code_line - dwriter->line;
unsigned int sp_opcode = 0;
if ( (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;
}
if ( sp_opcode == 0 ) {
if ( line_inc > 0 ) {
(void)sieve_binary_emit_byte(sblock, LINPROG_OP_ADVANCE_LINE);
(void)sieve_binary_emit_unsigned(sblock, 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);
}
if ( dwriter->column != code_column ) {
(void)sieve_binary_emit_byte(sblock, LINPROG_OP_SET_COLUMN);
(void)sieve_binary_emit_unsigned(sblock, code_column);
}
(void)sieve_binary_emit_byte(sblock, LINPROG_OP_COPY);
dwriter->address = code_address;
dwriter->line = code_line;
dwriter->column = code_column;
}
struct sieve_binary_debug_reader {
struct sieve_binary_block *sblock;
sieve_size_t address, last_address;
unsigned long int line, last_line;
unsigned long 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 long 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;
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;
}
debug_printf(" : + %d\n", value);
line += value;
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;
}