Skip to content

Commit 7dfe51b

Browse files
committed
v.0.8.11 Added controlflow graphs (cfg, vmcu_cfg_t) to libvmcu.
1 parent cea3f9e commit 7dfe51b

File tree

20 files changed

+569
-32
lines changed

20 files changed

+569
-32
lines changed

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
# Changelog
22

3-
# Unreleased
3+
# v.0.8.11 - 2021-07-07
4+
5+
- added: CFG - control flow graph
6+
- vmcu_cfg_t is the controlflow graph of libvmcu. It holds,
7+
- vmcu_cfg_t node*, a dynamic array of vmcu_node_t structures
8+
- node[0] is the entry node
9+
- a node consists of
10+
- vmcu_xref_t xto, a cross-reference to the corresponding instruction (xref-to)
11+
- vmcu_cfg_node_t *t, a node pointer for the true branch
12+
- vmcu_cfg_node_t *f, a node pointer for the false branch
13+
- int32_t used, a simple node counter, should be equal to report.progsize
14+
15+
- added: CFG example driver (driver/cfg/)
416

517
- using CMake now
618
- added syntax highlight for stepper driver

TODO.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
These are a some of my ideas for the future of libvmcu
44

5+
/********************************* Features ***************************************/
6+
57
[0] controlflow graph (cfg)
68
[0.1] requires slab allocator to minimize memory requests
79

@@ -31,4 +33,14 @@ These are a some of my ideas for the future of libvmcu
3133
[9] a small and very basic assembler (without macros, etc.) in order to allow code generation
3234

3335
[10] a python binding would be really great.
34-
[10.1] requires external contributors :( see CONTRIBUTING.txt
36+
[10.1] requires external contributors :( see CONTRIBUTING.txt
37+
38+
/********************************* Internal / Cleanup *****************************/
39+
40+
[11] sort instructions by address in disassembly (important)
41+
42+
[12] remove usage of basic integers (int) in libvmcu
43+
44+
[13] adjust driver makefiles (debug recipe, add -g -o)
45+
46+
[14] speed up controlflow analysis by adding a lookup table for the cfg nodes

driver/cfg/Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
TARGET := cfg
2+
LIB_DIR := ../../build-release
3+
LIB_DBG := ../../build-debug
4+
OBJ_DIR := $(BUILD)/objects
5+
INCLUDE := -I../../engine/include/libvmcu/
6+
LIBS := -lvmcu -lm
7+
8+
all: $(TARGET).c
9+
gcc $(INCLUDE) -c $(TARGET).c -o $(TARGET).o
10+
gcc -o $(TARGET) $(TARGET).o -L$(LIB_DIR)/ $(LIBS)
11+
@rm $(TARGET).o
12+
13+
debug: $(TARGET).c
14+
gcc $(INCLUDE) -c $(TARGET).c -g -o $(TARGET).o
15+
gcc -g -o $(TARGET) $(TARGET).o -L$(LIB_DBG)/ $(LIBS)
16+
@rm $(TARGET).o
17+
18+
clean:
19+
@-rm $(TARGET).o
20+
@-rm $(TARGET)

driver/cfg/cfg.c

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/* Controlflow Graph Driver for libvmcu */
2+
3+
// C Headers
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
8+
// libvmcu
9+
#include "libvmcu_analyzer.h"
10+
#include "libvmcu_system.h"
11+
12+
#define COLOR_RED "\x1b[31m"
13+
#define COLOR_GREEN "\x1b[32m"
14+
#define COLOR_YELLOW "\x1b[33m"
15+
#define COLOR_BLUE "\x1b[34m"
16+
#define COLOR_MAGENTA "\x1b[35m"
17+
#define COLOR_CYAN "\x1b[36m"
18+
#define COLOR_RESET "\x1b[0m"
19+
20+
#define mnemlen(mnem) strlen(mnem->base) \
21+
+ strlen(mnem->src) \
22+
+ strlen(mnem->dest)
23+
24+
/* libvmcu Structures */
25+
26+
vmcu_model_t *m328p = NULL;
27+
vmcu_report_t *report = NULL;
28+
29+
/* Forward Declaration of static Functions */
30+
31+
static void print_instruction(vmcu_instr_t *instr);
32+
static void print_instruction_details(vmcu_instr_t *instr);
33+
static void print_colored_base(const char *basestr, VMCU_GROUP group);
34+
static void print_colored_operands(const char *opstr, VMCU_OPTYPE optype);
35+
static void add_padding(const size_t length, const size_t max);
36+
static void cleanup(void);
37+
38+
/* --- Extern --- */
39+
40+
int main(const int argc, const char **argv) {
41+
42+
if(argc != 2) {
43+
44+
printf("Usage: ./skeleton <hexfile>\n");
45+
return EXIT_FAILURE;
46+
}
47+
48+
atexit(cleanup);
49+
50+
m328p = vmcu_model_ctor(VMCU_DEVICE_M328P);
51+
report = vmcu_analyze_ihex(argv[1], m328p);
52+
53+
if(report == NULL)
54+
return EXIT_FAILURE;
55+
56+
vmcu_cfg_t *cfg = report->cfg;
57+
58+
for(int32_t i = 0; i < cfg->used; i++) {
59+
60+
vmcu_cfg_node_t *node = &cfg->node[i];
61+
62+
printf(" ");
63+
print_instruction(node->xto.i);
64+
65+
if(node->t == NULL && node->f == NULL) {
66+
67+
printf(" ");
68+
printf("leaf instruction. no branches found.\n");
69+
}
70+
71+
if(node->t != NULL) {
72+
73+
printf("true branch: ");
74+
print_instruction(node->t->xto.i);
75+
}
76+
77+
if(node->f != NULL) {
78+
79+
printf("false branch: ");
80+
print_instruction(node->f->xto.i);
81+
}
82+
83+
printf("----------------------------------------\n");
84+
}
85+
86+
return EXIT_SUCCESS;
87+
}
88+
89+
/* --- Static --- */
90+
91+
static void print_instruction(vmcu_instr_t *instr) {
92+
93+
vmcu_mnemonic_t *mnem = &instr->mnem;
94+
95+
print_instruction_details(instr);
96+
print_colored_base(mnem->base, instr->group);
97+
98+
size_t sz = 0;
99+
100+
if(instr->dest.type != VMCU_OPTYPE_NONE) {
101+
102+
print_colored_operands(mnem->dest, instr->dest.type);
103+
sz += printf(", ");
104+
}
105+
106+
if(instr->src.type != VMCU_OPTYPE_NONE) {
107+
108+
print_colored_operands(mnem->src, instr->src.type);
109+
sz += printf(" ");
110+
}
111+
112+
add_padding(mnemlen(mnem) + sz, 26);
113+
printf("%s%s%s\n", COLOR_RED, mnem->comment, COLOR_RESET);
114+
}
115+
116+
static void print_instruction_details(vmcu_instr_t *instr) {
117+
118+
printf("0x%04x", instr->addr);
119+
120+
const uint16_t opcl = (instr->opcode & 0x0000ffff);
121+
const uint16_t swpl = (opcl >> 8) | (opcl << 8);
122+
123+
const uint16_t opch = ((instr->opcode & 0xffff0000) >> 16);
124+
const uint16_t swph = (opch >> 8) | (opch << 8);
125+
126+
if(instr->dword == false)
127+
printf(" %s....%s ", COLOR_GREEN, COLOR_RESET);
128+
else
129+
printf(" %s%04x%s ", COLOR_GREEN, swph, COLOR_RESET);
130+
131+
printf("%s%04x%s ", COLOR_YELLOW, swpl, COLOR_RESET);
132+
}
133+
134+
static void print_colored_base(const char *basestr, VMCU_GROUP group) {
135+
136+
switch(group) {
137+
138+
case VMCU_GROUP_NONE: printf("%s", COLOR_YELLOW); break;
139+
case VMCU_GROUP_MATH_LOGIC: printf("%s", COLOR_RED); break;
140+
case VMCU_GROUP_SYS_CTRL: printf("%s", COLOR_CYAN); break;
141+
case VMCU_GROUP_TRANSFER: printf("%s", COLOR_RESET); break;
142+
case VMCU_GROUP_FLOW: printf("%s", COLOR_GREEN); break;
143+
case VMCU_GROUP_BIT: printf("%s", COLOR_MAGENTA); break;
144+
145+
default: break;
146+
}
147+
148+
printf("%s%s ", basestr, COLOR_RESET);
149+
}
150+
151+
static void print_colored_operands(const char *opstr, VMCU_OPTYPE optype) {
152+
153+
switch(optype) {
154+
155+
case VMCU_OPTYPE_B:
156+
case VMCU_OPTYPE_K4:
157+
case VMCU_OPTYPE_K6:
158+
case VMCU_OPTYPE_K8:
159+
case VMCU_OPTYPE_IO5:
160+
case VMCU_OPTYPE_IO6:
161+
case VMCU_OPTYPE_D7:
162+
case VMCU_OPTYPE_D16:
163+
case VMCU_OPTYPE_P22:
164+
case VMCU_OPTYPE_S7:
165+
case VMCU_OPTYPE_S12:
166+
167+
printf("%s", COLOR_BLUE);
168+
169+
break;
170+
171+
case VMCU_OPTYPE_R:
172+
case VMCU_OPTYPE_RP:
173+
case VMCU_OPTYPE_X:
174+
case VMCU_OPTYPE_Y:
175+
case VMCU_OPTYPE_Z:
176+
177+
printf("%s", COLOR_CYAN);
178+
179+
break;
180+
181+
default: break;
182+
}
183+
184+
printf("%s%s", opstr, COLOR_RESET);
185+
}
186+
187+
static void add_padding(const size_t length, const size_t max) {
188+
189+
if(length >= max)
190+
return;
191+
192+
char pad[max - length + 1];
193+
194+
memset(pad, ' ', (max - length));
195+
pad[max - length] = '\0';
196+
197+
printf("%s", pad);
198+
}
199+
200+
static void cleanup(void) {
201+
202+
if(report != NULL)
203+
vmcu_report_dtor(report);
204+
205+
if(m328p != NULL)
206+
vmcu_model_dtor(m328p);
207+
}

driver/disasm/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ all: $(TARGET).c
1111
@rm $(TARGET).o
1212

1313
debug: $(TARGET).c
14-
gcc $(INCLUDE) -c $(TARGET).c -o $(TARGET).o
15-
gcc -o $(TARGET) $(TARGET).o -L$(LIB_DBG)/ $(LIBS)
14+
gcc $(INCLUDE) -c $(TARGET).c -g -o $(TARGET).o
15+
gcc -g -o $(TARGET) $(TARGET).o -L$(LIB_DBG)/ $(LIBS)
1616
@rm $(TARGET).o
1717

1818
clean:
1919
@-rm $(TARGET).o
20-
@-rm $(TARGET)
20+
@-rm $(TARGET)

driver/vector/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ all: $(TARGET).c
1111
@rm $(TARGET).o
1212

1313
debug: $(TARGET).c
14-
gcc $(INCLUDE) -c $(TARGET).c -o $(TARGET).o
15-
gcc -o $(TARGET) $(TARGET).o -L$(LIB_DBG)/ $(LIBS)
14+
gcc $(INCLUDE) -c $(TARGET).c -g -o $(TARGET).o
15+
gcc -g -o $(TARGET) $(TARGET).o -L$(LIB_DBG)/ $(LIBS)
1616
@rm $(TARGET).o
1717

1818
clean:
1919
@-rm $(TARGET).o
20-
@-rm $(TARGET)
20+
@-rm $(TARGET)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* Controlflow Analyzer Submodule Header */
2+
3+
#ifndef VMCU_CONTROL_FLOW_ANALYZER_H
4+
#define VMCU_CONTROL_FLOW_ANALYZER_H
5+
6+
typedef struct vmcu_model vmcu_model_t;
7+
typedef struct vmcu_report vmcu_report_t;
8+
9+
extern int vmcu_analyze_control_flow(vmcu_report_t *report, vmcu_model_t *mcu);
10+
11+
#endif
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/* Controlflow Graph Header */
2+
3+
#ifndef VMCU_CFG_H
4+
#define VMCU_CFG_H
5+
6+
// C Headers
7+
#include <inttypes.h>
8+
9+
// Project Headers (engine)
10+
#include "engine/include/analyzer/report/cfg_node.h"
11+
12+
typedef struct vmcu_cfg {
13+
14+
int32_t used;
15+
vmcu_cfg_node_t *node;
16+
17+
} vmcu_cfg_t;
18+
19+
extern vmcu_cfg_t* vmcu_cfg_ctor(const uint32_t capacity);
20+
extern void vmcu_cfg_dtor(vmcu_cfg_t *this);
21+
22+
#endif
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* CFG Node Header */
2+
3+
#ifndef VMCU_CFG_NODE_H
4+
#define VMCU_CFG_NODE_H
5+
6+
// Project Headers (engine)
7+
#include "engine/include/analyzer/report/xref.h"
8+
9+
typedef struct vmcu_cfg_node vmcu_cfg_node_t;
10+
11+
typedef struct vmcu_cfg_node {
12+
13+
vmcu_xref_t xto;
14+
15+
vmcu_cfg_node_t *t;
16+
vmcu_cfg_node_t *f;
17+
18+
} vmcu_cfg_node_t;
19+
20+
#endif

engine/include/analyzer/report/report.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@
77
#include <inttypes.h>
88

99
// Project Headers (engine)
10+
#include "engine/include/analyzer/report/cfg.h"
1011
#include "engine/include/analyzer/report/instr.h"
1112
#include "engine/include/analyzer/report/sfr.h"
1213
#include "engine/include/analyzer/report/label.h"
1314
#include "engine/include/analyzer/report/vector.h"
1415
#include "engine/include/analyzer/report/string.h"
1516

1617
typedef struct vmcu_report {
17-
18+
19+
vmcu_cfg_t *cfg;
20+
1821
int32_t progsize;
1922
vmcu_instr_t *disassembly;
2023

0 commit comments

Comments
 (0)