Coverage Report

Created: 2026-07-30 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/sieve-binary-debug.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "str.h"
5
6
#include "sieve-common.h"
7
#include "sieve-error.h"
8
#include "sieve-code.h"
9
10
#include "sieve-binary-private.h"
11
12
/* Quick 'n dirty debug */
13
#if 0
14
#define debug_printf(...) printf ("lineinfo: " __VA_ARGS__)
15
#else
16
#define debug_printf(...)
17
#endif
18
19
/*
20
 * Opcodes
21
 */
22
23
enum {
24
  LINPROG_OP_COPY,
25
  LINPROG_OP_ADVANCE_PC,
26
  LINPROG_OP_ADVANCE_LINE,
27
  LINPROG_OP_SET_COLUMN,
28
  LINPROG_OP_SPECIAL_BASE
29
};
30
31
0
#define LINPROG_LINE_BASE   0
32
0
#define LINPROG_LINE_RANGE  4
33
34
/*
35
 * Lineinfo writer
36
 */
37
38
struct sieve_binary_debug_writer {
39
  struct sieve_binary_block *sblock;
40
41
  sieve_size_t address;
42
  unsigned int line;
43
  unsigned int column;
44
};
45
46
struct sieve_binary_debug_writer *
47
sieve_binary_debug_writer_init(struct sieve_binary_block *sblock)
48
0
{
49
0
  struct sieve_binary_debug_writer *dwriter;
50
51
0
  dwriter = i_new(struct sieve_binary_debug_writer, 1);
52
0
  dwriter->sblock = sblock;
53
54
0
  return dwriter;
55
0
}
56
57
void sieve_binary_debug_writer_deinit(
58
  struct sieve_binary_debug_writer **dwriter)
59
0
{
60
0
  i_free(*dwriter);
61
0
  *dwriter = NULL;
62
0
}
63
64
void sieve_binary_debug_emit(struct sieve_binary_debug_writer *dwriter,
65
           sieve_size_t code_address, unsigned int code_line,
66
           unsigned int code_column)
67
0
{
68
0
  i_assert(code_address >= dwriter->address);
69
70
0
  struct sieve_binary_block *sblock = dwriter->sblock;
71
0
  sieve_size_t address_inc = code_address - dwriter->address;
72
0
  int line_inc = (code_line > dwriter->line ?
73
0
      (int)(code_line - dwriter->line) :
74
0
      -(int)(dwriter->line - code_line));
75
0
  unsigned int sp_opcode = 0;
76
77
  /* Check for applicability of special opcode */
78
0
  if (line_inc > 0 &&
79
0
      (LINPROG_LINE_BASE + LINPROG_LINE_RANGE - 1) >= line_inc) {
80
0
    sp_opcode = LINPROG_OP_SPECIAL_BASE +
81
0
      (line_inc - LINPROG_LINE_BASE) +
82
0
      (LINPROG_LINE_RANGE * address_inc);
83
84
0
    if (sp_opcode > 255)
85
0
      sp_opcode = 0;
86
0
  }
87
88
  /* Update line and address */
89
0
  if (sp_opcode == 0) {
90
0
    if (line_inc != 0) {
91
0
      (void)sieve_binary_emit_byte(sblock,
92
0
                 LINPROG_OP_ADVANCE_LINE);
93
0
      (void)sieve_binary_emit_unsigned(
94
0
        sblock, (unsigned int)line_inc);
95
0
    }
96
97
0
    if (address_inc > 0) {
98
0
      (void)sieve_binary_emit_byte(sblock,
99
0
                 LINPROG_OP_ADVANCE_PC);
100
0
      (void)sieve_binary_emit_unsigned(sblock, address_inc);
101
0
    }
102
0
  } else {
103
0
    (void)sieve_binary_emit_byte(sblock, sp_opcode);
104
0
  }
105
106
  /* Set column */
107
0
  if (dwriter->column != code_column) {
108
0
    (void)sieve_binary_emit_byte(sblock, LINPROG_OP_SET_COLUMN);
109
0
    (void)sieve_binary_emit_unsigned(sblock, code_column);
110
0
  }
111
112
  /* Generate matrix row */
113
0
  (void)sieve_binary_emit_byte(sblock, LINPROG_OP_COPY);
114
115
0
  dwriter->address = code_address;
116
0
  dwriter->line = code_line;
117
0
  dwriter->column = code_column;
118
0
}
119
120
/*
121
 * Debug reader
122
 */
123
124
struct sieve_binary_debug_reader {
125
  struct sieve_binary_block *sblock;
126
127
  sieve_size_t address, last_address;
128
  unsigned int line, last_line;
129
130
  unsigned int column;
131
132
  sieve_size_t state;
133
};
134
135
struct sieve_binary_debug_reader *
136
sieve_binary_debug_reader_init(struct sieve_binary_block *sblock)
137
0
{
138
0
  struct sieve_binary_debug_reader *dreader;
139
140
0
  dreader = i_new(struct sieve_binary_debug_reader, 1);
141
0
  dreader->sblock = sblock;
142
143
0
  return dreader;
144
0
}
145
146
void sieve_binary_debug_reader_deinit(
147
  struct sieve_binary_debug_reader **dreader)
148
0
{
149
0
  i_free(*dreader);
150
0
  *dreader = NULL;
151
0
}
152
153
void sieve_binary_debug_reader_reset(struct sieve_binary_debug_reader *dreader)
154
0
{
155
0
  dreader->address = 0;
156
0
  dreader->line = 0;
157
0
  dreader->column = 0;
158
0
  dreader->state = 0;
159
0
}
160
161
unsigned int
162
sieve_binary_debug_read_line(struct sieve_binary_debug_reader *dreader,
163
           sieve_size_t code_address)
164
0
{
165
0
  size_t linprog_size;
166
0
  sieve_size_t address;
167
0
  unsigned int line;
168
169
0
  if (code_address < dreader->last_address)
170
0
    sieve_binary_debug_reader_reset(dreader);
171
172
0
  if (code_address >= dreader->last_address &&
173
0
      code_address < dreader->address) {
174
0
    debug_printf("%08llx: NOOP [%08llx]\n",
175
0
           (unsigned long long)dreader->state,
176
0
           (unsigned long long)code_address);
177
0
    return dreader->last_line;
178
0
  }
179
180
0
  address = dreader->address;
181
0
  line = dreader->line;
182
183
0
  debug_printf("%08llx: READ [%08llx]\n",
184
0
         (unsigned long long)dreader->state,
185
0
         (unsigned long long)code_address);
186
187
0
  linprog_size = sieve_binary_block_get_size(dreader->sblock);
188
0
  while (dreader->state < linprog_size) {
189
0
    unsigned int opcode;
190
0
    unsigned int value;
191
0
    int line_inc;
192
193
0
    if (sieve_binary_read_byte(dreader->sblock,
194
0
             &dreader->state, &opcode)) {
195
0
      switch (opcode) {
196
0
      case LINPROG_OP_COPY:
197
0
        debug_printf("%08llx: COPY ==> %08llx: %ld\n",
198
0
               (unsigned long long)dreader->state,
199
0
               (unsigned long long)address, line);
200
201
0
        dreader->last_address = dreader->address;
202
0
        dreader->last_line = dreader->line;
203
204
0
        dreader->address = address;
205
0
        dreader->line = line;
206
207
0
        if (code_address < address)
208
0
          return dreader->last_line;
209
0
        else if (code_address == address)
210
0
          return dreader->line;
211
0
        break;
212
0
      case LINPROG_OP_ADVANCE_PC:
213
0
        debug_printf("%08llx: ADV_PC\n",
214
0
               (unsigned long long)dreader->state);
215
0
        if (!sieve_binary_read_unsigned(
216
0
          dreader->sblock, &dreader->state,
217
0
          &value)) {
218
0
          sieve_binary_debug_reader_reset(dreader);
219
0
          return 0;
220
0
        }
221
0
        debug_printf("        : + %d\n", value);
222
0
        address += value;
223
0
        break;
224
0
      case LINPROG_OP_ADVANCE_LINE:
225
0
        debug_printf("%08llx: ADV_LINE\n",
226
0
               (unsigned long long)dreader->state);
227
0
        if (!sieve_binary_read_unsigned(
228
0
          dreader->sblock, &dreader->state,
229
0
          &value)) {
230
0
          sieve_binary_debug_reader_reset(dreader);
231
0
          return 0;
232
0
        }
233
0
        line_inc = (int)value;
234
0
        debug_printf("        : + %d\n", line_inc);
235
0
        line = (line_inc > 0 ?
236
0
          line + (unsigned int)line_inc :
237
0
          line - (unsigned int)-line_inc);
238
0
        break;
239
0
      case LINPROG_OP_SET_COLUMN:
240
0
        debug_printf("%08llx: SET_COL\n",
241
0
               (unsigned long long)dreader->state);
242
0
        if (!sieve_binary_read_unsigned(
243
0
          dreader->sblock, &dreader->state,
244
0
          &value)) {
245
0
          sieve_binary_debug_reader_reset(dreader);
246
0
          return 0;
247
0
        }
248
0
        debug_printf("        : = %d\n", value);
249
0
        dreader->column = value;
250
0
        break;
251
0
      default:
252
0
        opcode -= LINPROG_OP_SPECIAL_BASE;
253
254
0
        address += (opcode / LINPROG_LINE_RANGE);
255
0
        line += LINPROG_LINE_BASE +
256
0
          (opcode % LINPROG_LINE_RANGE);
257
258
0
        debug_printf("%08llx: SPECIAL\n",
259
0
               (unsigned long long)dreader->state);
260
0
        debug_printf("        :  +A %d +L %d\n",
261
0
               (opcode / LINPROG_LINE_RANGE),
262
0
                LINPROG_LINE_BASE +
263
0
            (opcode % LINPROG_LINE_RANGE));
264
0
        break;
265
0
      }
266
0
    } else {
267
0
      debug_printf("OPCODE READ FAILED\n");
268
0
      sieve_binary_debug_reader_reset(dreader);
269
0
      return 0;
270
0
    }
271
0
  }
272
273
0
  return dreader->line;
274
0
}
275