forc-debug 0.66.6

Supports debugging Sway code via CLI and DAP server.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
use crate::{
    names::register_name,
    server::{
        AdapterError, DapServer, HandlerResult, INSTRUCTIONS_VARIABLE_REF, REGISTERS_VARIABLE_REF,
    },
};
use dap::{requests::VariablesArguments, responses::ResponseBody, types::Variable};
use fuel_vm::fuel_asm::{Imm06, Imm12, Imm18, Imm24, Instruction, RawInstruction, RegId};

impl DapServer {
    /// Processes a variables request, returning all variables and their current values.
    pub(crate) fn handle_variables_command(&self, args: &VariablesArguments) -> HandlerResult {
        let result = self.get_variables(args).map(|variables| {
            ResponseBody::Variables(dap::responses::VariablesResponse { variables })
        });
        match result {
            Ok(result) => HandlerResult::ok(result),
            Err(e) => HandlerResult::err_with_exit(e, 1),
        }
    }

    /// Returns the list of [Variable]s for the current execution state.
    pub(crate) fn get_variables(
        &self,
        args: &VariablesArguments,
    ) -> Result<Vec<Variable>, AdapterError> {
        let executor = self
            .state
            .executors
            .first()
            .ok_or(AdapterError::NoActiveTestExecutor)?;

        let register_variables = executor
            .interpreter
            .registers()
            .iter()
            .enumerate()
            .map(|(index, value)| Variable {
                name: register_name(index),
                value: format!("0x{value:X?}"),
                ..Default::default()
            })
            .collect::<Vec<_>>();

        // Slice out current opcode pc-4..pc and then parse using fuel-asm
        // to return the opcode and its arguments.
        let pc = executor.interpreter.registers()[RegId::PC] as usize;
        let instruction_variables = match Instruction::try_from(RawInstruction::from_be_bytes(
            executor.interpreter.memory()[pc..pc + 4]
                .try_into()
                .unwrap(),
        )) {
            Ok(instruction) => vec![
                ("Opcode", Some(format!("{:?}", instruction.opcode()))),
                ("rA", ra(instruction)),
                ("rB", rb(instruction)),
                ("rC", rc(instruction)),
                ("rD", rd(instruction)),
                ("imm", imm(instruction)),
            ]
            .iter()
            .filter_map(|(name, value)| {
                value.as_ref().map(|value| Variable {
                    name: (*name).to_string(),
                    value: value.to_string(),
                    ..Default::default()
                })
            })
            .collect(),
            Err(_) => vec![],
        };

        match args.variables_reference {
            REGISTERS_VARIABLE_REF => Ok(register_variables),
            INSTRUCTIONS_VARIABLE_REF => Ok(instruction_variables),
            _ => Ok(vec![]),
        }
    }
}

fn reg_id_to_string(reg_id: Option<RegId>) -> Option<String> {
    reg_id.map(|reg_id| register_name(reg_id.into()))
}

fn imm06_to_string(value: Imm06) -> Option<String> {
    Some(format!("0x{:X?}", value.to_u8()))
}

fn imm12_to_string(value: Imm12) -> Option<String> {
    Some(format!("0x{:X?}", value.to_u16()))
}

fn imm18_to_string(value: Imm18) -> Option<String> {
    Some(format!("0x{:X?}", value.to_u32()))
}

fn imm24_to_string(value: Imm24) -> Option<String> {
    Some(format!("0x{:X?}", value.to_u32()))
}

fn ra(instruction: Instruction) -> Option<String> {
    reg_id_to_string(match instruction {
        Instruction::ADD(op) => Some(op.ra()),
        Instruction::AND(op) => Some(op.ra()),
        Instruction::DIV(op) => Some(op.ra()),
        Instruction::EQ(op) => Some(op.ra()),
        Instruction::EXP(op) => Some(op.ra()),
        Instruction::GT(op) => Some(op.ra()),
        Instruction::LT(op) => Some(op.ra()),
        Instruction::MLOG(op) => Some(op.ra()),
        Instruction::MROO(op) => Some(op.ra()),
        Instruction::MOD(op) => Some(op.ra()),
        Instruction::MOVE(op) => Some(op.ra()),
        Instruction::MUL(op) => Some(op.ra()),
        Instruction::NOT(op) => Some(op.ra()),
        Instruction::OR(op) => Some(op.ra()),
        Instruction::SLL(op) => Some(op.ra()),
        Instruction::SRL(op) => Some(op.ra()),
        Instruction::SUB(op) => Some(op.ra()),
        Instruction::XOR(op) => Some(op.ra()),
        Instruction::MLDV(op) => Some(op.ra()),
        Instruction::RET(op) => Some(op.ra()),
        Instruction::RETD(op) => Some(op.ra()),
        Instruction::ALOC(op) => Some(op.ra()),
        Instruction::MCL(op) => Some(op.ra()),
        Instruction::MCP(op) => Some(op.ra()),
        Instruction::MEQ(op) => Some(op.ra()),
        Instruction::BHSH(op) => Some(op.ra()),
        Instruction::BHEI(op) => Some(op.ra()),
        Instruction::BURN(op) => Some(op.ra()),
        Instruction::CALL(op) => Some(op.ra()),
        Instruction::CCP(op) => Some(op.ra()),
        Instruction::CROO(op) => Some(op.ra()),
        Instruction::CSIZ(op) => Some(op.ra()),
        Instruction::CB(op) => Some(op.ra()),
        Instruction::LDC(op) => Some(op.ra()),
        Instruction::LOG(op) => Some(op.ra()),
        Instruction::LOGD(op) => Some(op.ra()),
        Instruction::MINT(op) => Some(op.ra()),
        Instruction::RVRT(op) => Some(op.ra()),
        Instruction::SCWQ(op) => Some(op.ra()),
        Instruction::SRW(op) => Some(op.ra()),
        Instruction::SRWQ(op) => Some(op.ra()),
        Instruction::SWW(op) => Some(op.ra()),
        Instruction::SWWQ(op) => Some(op.ra()),
        Instruction::TR(op) => Some(op.ra()),
        Instruction::TRO(op) => Some(op.ra()),
        Instruction::ECK1(op) => Some(op.ra()),
        Instruction::ECR1(op) => Some(op.ra()),
        Instruction::ED19(op) => Some(op.ra()),
        Instruction::K256(op) => Some(op.ra()),
        Instruction::S256(op) => Some(op.ra()),
        Instruction::TIME(op) => Some(op.ra()),
        Instruction::FLAG(op) => Some(op.ra()),
        Instruction::BAL(op) => Some(op.ra()),
        Instruction::JMP(op) => Some(op.ra()),
        Instruction::JNE(op) => Some(op.ra()),
        Instruction::SMO(op) => Some(op.ra()),
        Instruction::ADDI(op) => Some(op.ra()),
        Instruction::ANDI(op) => Some(op.ra()),
        Instruction::DIVI(op) => Some(op.ra()),
        Instruction::EXPI(op) => Some(op.ra()),
        Instruction::MODI(op) => Some(op.ra()),
        Instruction::MULI(op) => Some(op.ra()),
        Instruction::ORI(op) => Some(op.ra()),
        Instruction::SLLI(op) => Some(op.ra()),
        Instruction::SRLI(op) => Some(op.ra()),
        Instruction::SUBI(op) => Some(op.ra()),
        Instruction::XORI(op) => Some(op.ra()),
        Instruction::JNEI(op) => Some(op.ra()),
        Instruction::LB(op) => Some(op.ra()),
        Instruction::LW(op) => Some(op.ra()),
        Instruction::SB(op) => Some(op.ra()),
        Instruction::SW(op) => Some(op.ra()),
        Instruction::MCPI(op) => Some(op.ra()),
        Instruction::GTF(op) => Some(op.ra()),
        Instruction::MCLI(op) => Some(op.ra()),
        Instruction::GM(op) => Some(op.ra()),
        Instruction::MOVI(op) => Some(op.ra()),
        Instruction::JNZI(op) => Some(op.ra()),
        Instruction::JMPF(op) => Some(op.ra()),
        Instruction::JMPB(op) => Some(op.ra()),
        Instruction::JNZF(op) => Some(op.ra()),
        Instruction::JNZB(op) => Some(op.ra()),
        Instruction::JNEF(op) => Some(op.ra()),
        Instruction::JNEB(op) => Some(op.ra()),
        Instruction::CFE(op) => Some(op.ra()),
        Instruction::CFS(op) => Some(op.ra()),
        Instruction::WDCM(op) => Some(op.ra()),
        Instruction::WQCM(op) => Some(op.ra()),
        Instruction::WDOP(op) => Some(op.ra()),
        Instruction::WQOP(op) => Some(op.ra()),
        Instruction::WDML(op) => Some(op.ra()),
        Instruction::WQML(op) => Some(op.ra()),
        Instruction::WDDV(op) => Some(op.ra()),
        Instruction::WQDV(op) => Some(op.ra()),
        Instruction::WDMD(op) => Some(op.ra()),
        Instruction::WQMD(op) => Some(op.ra()),
        Instruction::WDAM(op) => Some(op.ra()),
        Instruction::WQAM(op) => Some(op.ra()),
        Instruction::WDMM(op) => Some(op.ra()),
        Instruction::WQMM(op) => Some(op.ra()),
        Instruction::ECAL(op) => Some(op.ra()),
        _ => None,
    })
}

fn rb(instruction: Instruction) -> Option<String> {
    reg_id_to_string(match instruction {
        Instruction::ADD(op) => Some(op.rb()),
        Instruction::AND(op) => Some(op.rb()),
        Instruction::DIV(op) => Some(op.rb()),
        Instruction::EQ(op) => Some(op.rb()),
        Instruction::EXP(op) => Some(op.rb()),
        Instruction::GT(op) => Some(op.rb()),
        Instruction::LT(op) => Some(op.rb()),
        Instruction::MLOG(op) => Some(op.rb()),
        Instruction::MROO(op) => Some(op.rb()),
        Instruction::MOD(op) => Some(op.rb()),
        Instruction::MOVE(op) => Some(op.rb()),
        Instruction::MUL(op) => Some(op.rb()),
        Instruction::NOT(op) => Some(op.rb()),
        Instruction::OR(op) => Some(op.rb()),
        Instruction::SLL(op) => Some(op.rb()),
        Instruction::SRL(op) => Some(op.rb()),
        Instruction::SUB(op) => Some(op.rb()),
        Instruction::XOR(op) => Some(op.rb()),
        Instruction::MLDV(op) => Some(op.rb()),
        Instruction::RETD(op) => Some(op.rb()),
        Instruction::MCL(op) => Some(op.rb()),
        Instruction::MCP(op) => Some(op.rb()),
        Instruction::MEQ(op) => Some(op.rb()),
        Instruction::BHSH(op) => Some(op.rb()),
        Instruction::BURN(op) => Some(op.rb()),
        Instruction::CALL(op) => Some(op.rb()),
        Instruction::CCP(op) => Some(op.rb()),
        Instruction::CROO(op) => Some(op.rb()),
        Instruction::CSIZ(op) => Some(op.rb()),
        Instruction::LDC(op) => Some(op.rb()),
        Instruction::LOG(op) => Some(op.rb()),
        Instruction::LOGD(op) => Some(op.rb()),
        Instruction::MINT(op) => Some(op.rb()),
        Instruction::SCWQ(op) => Some(op.rb()),
        Instruction::SRW(op) => Some(op.rb()),
        Instruction::SRWQ(op) => Some(op.rb()),
        Instruction::SWW(op) => Some(op.rb()),
        Instruction::SWWQ(op) => Some(op.rb()),
        Instruction::TR(op) => Some(op.rb()),
        Instruction::TRO(op) => Some(op.rb()),
        Instruction::ECK1(op) => Some(op.rb()),
        Instruction::ECR1(op) => Some(op.rb()),
        Instruction::ED19(op) => Some(op.rb()),
        Instruction::K256(op) => Some(op.rb()),
        Instruction::S256(op) => Some(op.rb()),
        Instruction::TIME(op) => Some(op.rb()),
        Instruction::BAL(op) => Some(op.rb()),
        Instruction::JNE(op) => Some(op.rb()),
        Instruction::SMO(op) => Some(op.rb()),
        Instruction::ADDI(op) => Some(op.rb()),
        Instruction::ANDI(op) => Some(op.rb()),
        Instruction::DIVI(op) => Some(op.rb()),
        Instruction::EXPI(op) => Some(op.rb()),
        Instruction::MODI(op) => Some(op.rb()),
        Instruction::MULI(op) => Some(op.rb()),
        Instruction::ORI(op) => Some(op.rb()),
        Instruction::SLLI(op) => Some(op.rb()),
        Instruction::SRLI(op) => Some(op.rb()),
        Instruction::SUBI(op) => Some(op.rb()),
        Instruction::XORI(op) => Some(op.rb()),
        Instruction::JNEI(op) => Some(op.rb()),
        Instruction::LB(op) => Some(op.rb()),
        Instruction::LW(op) => Some(op.rb()),
        Instruction::SB(op) => Some(op.rb()),
        Instruction::SW(op) => Some(op.rb()),
        Instruction::MCPI(op) => Some(op.rb()),
        Instruction::GTF(op) => Some(op.rb()),
        Instruction::JNZF(op) => Some(op.rb()),
        Instruction::JNZB(op) => Some(op.rb()),
        Instruction::JNEF(op) => Some(op.rb()),
        Instruction::JNEB(op) => Some(op.rb()),
        Instruction::WDCM(op) => Some(op.rb()),
        Instruction::WQCM(op) => Some(op.rb()),
        Instruction::WDOP(op) => Some(op.rb()),
        Instruction::WQOP(op) => Some(op.rb()),
        Instruction::WDML(op) => Some(op.rb()),
        Instruction::WQML(op) => Some(op.rb()),
        Instruction::WDDV(op) => Some(op.rb()),
        Instruction::WQDV(op) => Some(op.rb()),
        Instruction::WDMD(op) => Some(op.rb()),
        Instruction::WQMD(op) => Some(op.rb()),
        Instruction::WDAM(op) => Some(op.rb()),
        Instruction::WQAM(op) => Some(op.rb()),
        Instruction::WDMM(op) => Some(op.rb()),
        Instruction::WQMM(op) => Some(op.rb()),
        Instruction::ECAL(op) => Some(op.rb()),
        _ => None,
    })
}

fn rc(instruction: Instruction) -> Option<String> {
    reg_id_to_string(match instruction {
        Instruction::ADD(op) => Some(op.rc()),
        Instruction::AND(op) => Some(op.rc()),
        Instruction::DIV(op) => Some(op.rc()),
        Instruction::EQ(op) => Some(op.rc()),
        Instruction::EXP(op) => Some(op.rc()),
        Instruction::GT(op) => Some(op.rc()),
        Instruction::LT(op) => Some(op.rc()),
        Instruction::MLOG(op) => Some(op.rc()),
        Instruction::MROO(op) => Some(op.rc()),
        Instruction::MOD(op) => Some(op.rc()),
        Instruction::MUL(op) => Some(op.rc()),
        Instruction::OR(op) => Some(op.rc()),
        Instruction::SLL(op) => Some(op.rc()),
        Instruction::SRL(op) => Some(op.rc()),
        Instruction::SUB(op) => Some(op.rc()),
        Instruction::XOR(op) => Some(op.rc()),
        Instruction::MLDV(op) => Some(op.rc()),
        Instruction::MCP(op) => Some(op.rc()),
        Instruction::MEQ(op) => Some(op.rc()),
        Instruction::CALL(op) => Some(op.rc()),
        Instruction::CCP(op) => Some(op.rc()),
        Instruction::LDC(op) => Some(op.rc()),
        Instruction::LOG(op) => Some(op.rc()),
        Instruction::LOGD(op) => Some(op.rc()),
        Instruction::SCWQ(op) => Some(op.rc()),
        Instruction::SRW(op) => Some(op.rc()),
        Instruction::SRWQ(op) => Some(op.rc()),
        Instruction::SWW(op) => Some(op.rc()),
        Instruction::SWWQ(op) => Some(op.rc()),
        Instruction::TR(op) => Some(op.rc()),
        Instruction::TRO(op) => Some(op.rc()),
        Instruction::ECK1(op) => Some(op.rc()),
        Instruction::ECR1(op) => Some(op.rc()),
        Instruction::ED19(op) => Some(op.rc()),
        Instruction::K256(op) => Some(op.rc()),
        Instruction::S256(op) => Some(op.rc()),
        Instruction::BAL(op) => Some(op.rc()),
        Instruction::JNE(op) => Some(op.rc()),
        Instruction::SMO(op) => Some(op.rc()),
        Instruction::JNEF(op) => Some(op.rc()),
        Instruction::JNEB(op) => Some(op.rc()),
        Instruction::WDCM(op) => Some(op.rc()),
        Instruction::WQCM(op) => Some(op.rc()),
        Instruction::WDOP(op) => Some(op.rc()),
        Instruction::WQOP(op) => Some(op.rc()),
        Instruction::WDML(op) => Some(op.rc()),
        Instruction::WQML(op) => Some(op.rc()),
        Instruction::WDDV(op) => Some(op.rc()),
        Instruction::WQDV(op) => Some(op.rc()),
        Instruction::WDMD(op) => Some(op.rc()),
        Instruction::WQMD(op) => Some(op.rc()),
        Instruction::WDAM(op) => Some(op.rc()),
        Instruction::WQAM(op) => Some(op.rc()),
        Instruction::WDMM(op) => Some(op.rc()),
        Instruction::WQMM(op) => Some(op.rc()),
        Instruction::ECAL(op) => Some(op.rc()),
        _ => None,
    })
}

fn rd(instruction: Instruction) -> Option<String> {
    reg_id_to_string(match instruction {
        Instruction::MLDV(op) => Some(op.rd()),
        Instruction::MEQ(op) => Some(op.rd()),
        Instruction::CALL(op) => Some(op.rd()),
        Instruction::CCP(op) => Some(op.rd()),
        Instruction::LOG(op) => Some(op.rd()),
        Instruction::LOGD(op) => Some(op.rd()),
        Instruction::SRWQ(op) => Some(op.rd()),
        Instruction::SWWQ(op) => Some(op.rd()),
        Instruction::TRO(op) => Some(op.rd()),
        Instruction::WDMD(op) => Some(op.rd()),
        Instruction::WQMD(op) => Some(op.rd()),
        Instruction::WDAM(op) => Some(op.rd()),
        Instruction::WQAM(op) => Some(op.rd()),
        Instruction::WDMM(op) => Some(op.rd()),
        Instruction::WQMM(op) => Some(op.rd()),
        Instruction::ECAL(op) => Some(op.rd()),
        _ => None,
    })
}

fn imm(instruction: Instruction) -> Option<String> {
    match instruction {
        Instruction::ADDI(op) => imm12_to_string(op.imm12()),
        Instruction::ANDI(op) => imm12_to_string(op.imm12()),
        Instruction::DIVI(op) => imm12_to_string(op.imm12()),
        Instruction::EXPI(op) => imm12_to_string(op.imm12()),
        Instruction::MODI(op) => imm12_to_string(op.imm12()),
        Instruction::MULI(op) => imm12_to_string(op.imm12()),
        Instruction::ORI(op) => imm12_to_string(op.imm12()),
        Instruction::SLLI(op) => imm12_to_string(op.imm12()),
        Instruction::SRLI(op) => imm12_to_string(op.imm12()),
        Instruction::SUBI(op) => imm12_to_string(op.imm12()),
        Instruction::XORI(op) => imm12_to_string(op.imm12()),
        Instruction::JNEI(op) => imm12_to_string(op.imm12()),
        Instruction::LB(op) => imm12_to_string(op.imm12()),
        Instruction::LW(op) => imm12_to_string(op.imm12()),
        Instruction::SB(op) => imm12_to_string(op.imm12()),
        Instruction::SW(op) => imm12_to_string(op.imm12()),
        Instruction::MCPI(op) => imm12_to_string(op.imm12()),
        Instruction::GTF(op) => imm12_to_string(op.imm12()),
        Instruction::MCLI(op) => imm18_to_string(op.imm18()),
        Instruction::GM(op) => imm18_to_string(op.imm18()),
        Instruction::MOVI(op) => imm18_to_string(op.imm18()),
        Instruction::JNZI(op) => imm18_to_string(op.imm18()),
        Instruction::JMPF(op) => imm18_to_string(op.imm18()),
        Instruction::JMPB(op) => imm18_to_string(op.imm18()),
        Instruction::JNZF(op) => imm12_to_string(op.imm12()),
        Instruction::JNZB(op) => imm12_to_string(op.imm12()),
        Instruction::JNEF(op) => imm06_to_string(op.imm06()),
        Instruction::JNEB(op) => imm06_to_string(op.imm06()),
        Instruction::JI(op) => imm24_to_string(op.imm24()),
        Instruction::CFEI(op) => imm24_to_string(op.imm24()),
        Instruction::CFSI(op) => imm24_to_string(op.imm24()),
        Instruction::PSHL(op) => imm24_to_string(op.imm24()),
        Instruction::PSHH(op) => imm24_to_string(op.imm24()),
        Instruction::POPL(op) => imm24_to_string(op.imm24()),
        Instruction::POPH(op) => imm24_to_string(op.imm24()),
        Instruction::WDCM(op) => imm06_to_string(op.imm06()),
        Instruction::WQCM(op) => imm06_to_string(op.imm06()),
        Instruction::WDOP(op) => imm06_to_string(op.imm06()),
        Instruction::WQOP(op) => imm06_to_string(op.imm06()),
        Instruction::WDML(op) => imm06_to_string(op.imm06()),
        Instruction::WQML(op) => imm06_to_string(op.imm06()),
        Instruction::WDDV(op) => imm06_to_string(op.imm06()),
        Instruction::WQDV(op) => imm06_to_string(op.imm06()),
        _ => None,
    }
}