
Libvmcu - это небольшой двигатель для статического и динамического анализа двоичных файлов микроконтроллера AVR.
Он заботится о подготовке необработанных данных, которые затем могут быть дополнительно обработаны другими программами. Цель здесь состоит в том, чтобы позволить программно взаимодействовать с исходным кодом AVR.
libvmcu предоставляет вам
Примечание: эта библиотека все еще находится в разработке.
Я примеры
II витрина
III установка VMCU
IV поддержал MCU
V Динамический анализ
VI Статический анализ
Vii инструкции
Viii привязки
IX вносит свой вклад
X кредиты
XI документация
/* A possible implementation of print_instruction can be found below */
int main ( const int argc , const char * * argv ) {
/* ignoring checks for this example */
vmcu_model_t * m328p = vmcu_model_ctor ( VMCU_DEVICE_M328P );
vmcu_report_t * report = vmcu_analyze_file ( "file.hex" , m328p );
for ( uint32_t i = 0 ; i < report -> cfg -> used ; i ++ ) {
vmcu_cfg_node_t * node = & report -> cfg -> node [ i ];
print_instruction ( node -> xto . i );
if ( node -> t != NULL ) {
printf ( "true -> " );
print_instruction ( node -> t -> xto . i );
}
if ( node -> f != NULL ) {
printf ( "false -> " );
print_instruction ( node -> f -> xto . i );
}
printf ( "n" );
}
vmcu_report_dtor ( report );
vmcu_model_dtor ( m328p );
return EXIT_SUCCESS ;
} 0x0000 .... f1f3 breq - 2 ; (ZF == 1): PC <- PC + -2 + 1
true - > 0x3fff .... 839a sbi 0x10 , 3 ; IO[0x10, 3] <- 1
false - > 0x0001 .... 0fef ldi r16 , 0xff ; r16 <- 0xff
--------------------------------------------------------------------------------
0x0001 .... 0fef ldi r16 , 0xff ; r16 <- 0xff
true - > 0x0002 .... 5817 cp r21 , r24 ; r21 - r24
--------------------------------------------------------------------------------
0x0002 .... 5817 cp r21 , r24 ; r21 - r24
true - > 0x0003 .... 19f4 brne 3 ; (ZF == 0): PC <- PC + 3 + 1
--------------------------------------------------------------------------------
0x0003 .... 19f4 brne 3 ; (ZF == 0): PC <- PC + 3 + 1
true - > 0x0007 .... 0127 eor r16 , r17 ; r16 <- r16 ^ r17
false - > 0x0004 .... a895 wdr ; watchdog reset
--------------------------------------------------------------------------------
0x0004 .... a895 wdr ; watchdog reset
true - > 0x0005 .... 8895 sleep ; circuit sleep
--------------------------------------------------------------------------------
0x0005 .... 8895 sleep ; circuit sleep
true - > 0x0006 .... 0000 nop ; no operation
--------------------------------------------------------------------------------
0x0006 .... 0000 nop ; no operation
true - > 0x0007 .... 0127 eor r16 , r17 ; r16 <- r16 ^ r17
--------------------------------------------------------------------------------
0x0007 .... 0127 eor r16 , r17 ; r16 <- r16 ^ r17
--------------------------------------------------------------------------------
0x3fff .... 839a sbi 0x10 , 3 ; IO[0x10, 3] <- 1
true - > 0x0000 .... f1f3 breq - 2 ; (ZF == 1): PC <- PC + -2 + 1
-------------------------------------------------------------------------------- /* A possible implementation of print_instruction can be found below */
int main ( const int argc , const char * * argv ) {
/* ignoring checks for this example */
vmcu_model_t * m328p = vmcu_model_ctor ( VMCU_DEVICE_M328P );
vmcu_report_t * report = vmcu_analyze_file ( "file.srec" , m328p );
for ( uint32_t i = 0 ; i < report -> progsize ; i ++ ) {
printf ( "0x%04x " , report -> disassembly [ i ]. addr );
print_instruction ( & report -> disassembly [ i ]);
}
vmcu_report_dtor ( report );
vmcu_model_dtor ( m328p );
return EXIT_SUCCESS ;
} 0x004e ldi r27 , 0x06 ; r27 <- 0x06
0x004f rjmp 1 ; PC <- PC + 1 + 1
0x0050 st X +, r1 ; DS[X+] <- r1
0x0051 cpi r26 , 0x20 ; r26 - 0x20
0x0052 cpc r27 , r18 ; r27 - r18 - CF
0x0053 brne - 4 ; (ZF == 0): PC <- PC + -4 + 1
0x0054 call 0x60b ; PC <- 0x60b /* A possible implementation of print_instruction can be found below */
int main ( const int argc , const char * * argv ) {
/* ignoring checks for this example */
vmcu_model_t * m328p = vmcu_model_ctor ( VMCU_DEVICE_M328P );
vmcu_report_t * report = vmcu_analyze_file ( "file.hex" , m328p );
for ( uint32_t i = 0 ; i < report -> progsize ; i ++ ) {
vmcu_instr_t * instr = & report -> disassembly [ i ];
if ( instr -> writes . c_flag == true)
print_instruction ( instr );
if ( instr -> reads . c_flag == true)
print_instruction ( instr );
}
vmcu_report_dtor ( report );
vmcu_model_dtor ( m328p );
return EXIT_SUCCESS ;
} subi r18 , 0x00 ; r18 <- r18 - 0x00
adiw r29:r28 , 0x1a ; r29:r28 <- r29:r28 + 0x1a
sbci r23 , 0xff ; r23 <- r23 - 0xff - CF
cpc r19 , r17 ; r19 - r17 - CF int main ( const int argc , const char * * argv ) {
/* ignoring checks for this example */
vmcu_model_t * m328p = vmcu_model_ctor ( VMCU_DEVICE_M328P );
vmcu_report_t * report = vmcu_analyze_file ( "file.hex" , m328p );
for ( uint32_t i = 0 ; i < report -> n_vector ; i ++ ) {
vmcu_vector_t * vect = & report -> vector [ i ];
vmcu_instr_t * isr = vect -> xto -> i ;
printf ( "Vector ID %d @ 0x%04xn" , vect -> id , vect -> addr );
printf ( " interrupt service routine at 0x%04x" , isr -> addr );
printf ( "nn" );
}
vmcu_report_dtor ( report );
vmcu_model_dtor ( m328p );
return EXIT_SUCCESS ;
} Vector ID 16 @ 0x0020
interrupt service routine at 0x03f5
Vector ID 17 @ 0x0022
interrupt service routine at 0x008a
Vector ID 18 @ 0x0024
interrupt service routine at 0x03c3
Vector ID 19 @ 0x0026
interrupt service routine at 0x039d /* A possible implementation of print_instruction can be found below */
int main ( const int argc , const char * * argv ) {
/* ignoring checks for this example */
vmcu_model_t * m328p = vmcu_model_ctor ( VMCU_DEVICE_M328P );
vmcu_report_t * report = vmcu_analyze_file ( "file.hex" , m328p );
for ( uint32_t i = 0 ; i < report -> n_label ; i ++ ) {
vmcu_label_t * lx = & report -> label [ i ];
printf ( "0x%04xtL%dnn" , lx -> addr , lx -> id );
for ( uint32_t j = 0 ; j < lx -> n_xfrom ; j ++ ) {
vmcu_xref_t * x = & lx -> xfrom [ j ];
printf ( " xref from 0x%04x " , x -> i -> addr );
print_instruction ( x -> i );
}
printf ( "n" );
}
vmcu_report_dtor ( report );
vmcu_model_dtor ( m328p );
return EXIT_SUCCESS ;
} 0x04c6 L75
xref from 0x04a1 call + 1222 ; PC <- 0x4c6
xref from 0x0a84 call + 1222 ; PC <- 0x4c6
xref from 0x0b5c call + 1222 ; PC <- 0x4c6
0x04e2 L76
xref from 0x05d4 rjmp - 243 ; PC <- PC - 0xf3 + 1
0x05d0 L77
xref from 0x04e1 rjmp + 238 ; PC <- PC + 0xee + 1 /* A possible implementation of print_instruction can be found below */
int main ( const int argc , const char * * argv ) {
/* ignoring checks for this example */
vmcu_model_t * m328p = vmcu_model_ctor ( VMCU_DEVICE_M328P );
vmcu_report_t * report = vmcu_analyze_file ( "file.hex" , m328p );
for ( uint32_t i = 0 ; i < report -> n_sfr ; i ++ ) {
vmcu_sfr_t * sfr = & report -> sfr [ i ];
printf ( "SFR ID: %dnn" , sfr -> id );
for ( uint32_t j = 0 ; j < sfr -> n_xfrom ; j ++ ) {
vmcu_xref_t * x = & sfr -> xfrom [ j ];
printf ( " xref from 0x%04x " , x -> i -> addr );
print_instruction ( x -> i );
}
printf ( "n" );
}
vmcu_report_dtor ( report );
vmcu_model_dtor ( m328p );
return EXIT_SUCCESS ;
} SFR ID: 17
xref from 0x00f4 sbi 0x1f , 2 ; IO[1f, 2] <- 0x01
xref from 0x00f5 sbi 0x1f , 1 ; IO[1f, 1] <- 0x01
SFR ID: 50
xref from 0x004c sts 0x006e , r1 ; DATA[0x6e] <- R1
xref from 0x0051 lds r24 , 0x006e ; R24 <- DATA[0x6e]
xref from 0x0054 sts 0x006e , r24 ; DATA[0x6e] <- R24 /* 0x6a97 (little endian) <=> sbiw r29:r28, 0x1a */
int main ( const int argc , const char * * argv ) {
/* initialize a device model */
vmcu_model_t * m328p = vmcu_model_ctor ( VMCU_DEVICE_M328P );
vmcu_instr_t instr ;
vmcu_disassemble_bytes ( 0x6a97 , & instr , m328p );
const VMCU_IKEY key = instr . key ; // VMCU_IKEY_SBIW
const VMCU_GROUP grp = instr . group ; // VMCU_GROUP_MATH_LOGIC
const uint32_t opcode = instr . opcode ; // 0x976a (big endian)
const uint32_t addr = instr . addr ; // 0x0000 (undefined)
const bool dword = instr . dword ; // false
const bool exec = instr . exec ; // true
vmcu_operand_t * src = & instr . src ; // source operand
vmcu_operand_t * dest = & instr . dest ; // destination operand
VMCU_OPTYPE src_type = src -> type ; // VMCU_OPTYPE_K6
VMCU_OPTYPE dest_type = dest -> type ; // VMCU_OPTYPE_RP
const uint8_t src_val = src -> k ; // 0x1a
VMCU_REGISTER dest_rh = dest -> rp . high ; // VMCU_REGISTER_R29
VMCU_REGISTER dest_rl = dest -> rp . low ; // VMCU_REGISTER_R28
const bool writes_hf = instr . writes . h_flag ; // false
const bool writes_cf = instr . writes . c_flag ; // true
const bool reads_io = instr . reads . io ; // false
const bool reads_nf = instr . reads . n_flag ; // false
vmcu_mnemonic_t * mnem = & instr . mnem ; // instruction mnemonic
const char * base_str = mnem -> base ; // "sbiw"
const char * dest_str = mnem -> dest ; // "r29:r28"
const char * src_str = mnem -> src ; // "0x1a"
const char * com_str = mnem -> comment ; // "r29:r28 <- r29:r28 - 0x1a"
vmcu_model_dtor ( m328p );
return EXIT_SUCCESS ;
} /* this snippet can be used to assemble and print an instruction */
void print_instruction ( const vmcu_instr_t * instr ) {
printf ( "%s" , instr -> mnem . base );
if ( instr -> dest . type != VMCU_OPTYPE_NONE )
printf ( " %s," , instr -> mnem . dest );
if ( instr -> src . type != VMCU_OPTYPE_NONE )
printf ( " %s" , instr -> mnem . src );
printf ( " %sn" , instr -> mnem . comment );
}
Небольшой отладчик, написанный с Libvmcu
В настоящее время эта библиотека поставляется с двумя заголовками, оба можно найти в Engine/include/libvmcu:
Допустим, у нас есть файл, называемый prog.c на верхнем уровне этого репозитория, и мы хотим связать его с Libvmcu:
/* prog.c */
#include "libvmcu_analyzer.h"
#include "libvmcu_system.h"
int main ( void ) {
/* do something */
return 0 ;
} You@Terminal:~ $ cd build-release/
You@Terminal:~ $ make -f build.mk You@Terminal:~ $ gcc -Iengine/include/libvmcu/ -c prog.c -o prog.o You@Terminal:~ $ gcc -o prog prog.o -Lbuild-release/ -lvmcu -lmВот и все. Если вы столкнетесь с проблемами, посмотрите на некоторые примеры в драйвере/ каталоге.
Libvmcu пытается поддержать как можно больше типов AVR для статического анализа. Динамический анализ в настоящее время запланирован только для семьи ATMEGA328, но может быть расширен в будущем.
Это должно быть довольно легко добавить новые микроконтроллеры в статический анализ. Для получения дополнительной информации взгляните на двигатель/*/arch/
AVR Device Core
AVRE DEVICE CORE
AVRE+ DEVICE CORE
AVRXM DEVICE CORE
Avrxt Device Core
AVRRC Device Core
Дизассемблер
Перекрестные ссылки (xref-from, xref-to)
Флаги анализатора
разложить и классифицировать инструкции
Анализатор для бинарных файлов AVR
Читатель формата
поддержка прерывания
Точное моделирование цикла в реальном времени
Поддержка 133 инструкции по сборке AVR
точное моделирование внутренних периферийных устройств
В настоящее время VMCU поддерживает: ~ 133 инструкции. Таким образом, несколько инструкций выполняются как инструкции «NOP», поэтому не имеют реальной функциональности. Эти инструкции будут реализованы как можно скорее. Следующие инструкции требуют дальнейшей работы:
Все остальные инструкции по сборке работают просто отлично.
Libvmcu имеет Java -привязки для основных функций. Для получения дополнительной информации взгляните на привязки/java/
Также обратите внимание, что привязки не всегда могут работать с последней версией из -за разработки двигателя.
| Двигатель | Водители | Привязки | Тестирование |
|---|---|---|---|
| закрыт для пиара | Открыт для Pr | Открыт для Pr | Открыт для Pr |
К моменту написания этого документация все еще находится в разработке. (Неполная) документация можно найти по адресу https://github.com/milo-d/libvmcu-virtual-mcu-library/wiki
Если вам не хватает информации и не хотите ждать вики, файлы заголовка Libvmcu также довольно хорошо задокументированы.