
LIBVMCU est un petit moteur pour l'analyse statique et dynamique des binaires de microcontrôleur AVR.
Il s'occupe de la préparation de données brutes, qui peuvent ensuite être traitées davantage par d'autres programmes. L'objectif ici est de permettre d'interagir par programme avec le code source AVR.
libvmcu vous fournit
Remarque: cette bibliothèque est toujours en développement.
I Exemples
II vitrine
III Configuration VMCU
IV a pris en charge les MCU
V Analyse dynamique
VI Analyse statique
VII
VIII Régales
IX Contribution
X crédits
Documentation 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 );
}
Un petit débogueur écrit avec libvmcu
Actuellement, cette bibliothèque est livrée avec deux en-têtes, les deux peuvent être trouvées dans le moteur / inclure / libvmcu:
Disons que nous avons un fichier appelé prog.c au niveau supérieur de ce référentiel et nous voulons le relier à 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 -lmC'est ça. Si vous rencontrez des problèmes, regardez quelques exemples dans le pilote / répertoire.
Libvmcu essaie de prendre en charge autant de types AVR que possible pour l'analyse statique. L'analyse dynamique n'est actuellement prévue que pour la famille Atmega328, mais peut être étendue à l'avenir.
Il devrait être assez facile d'ajouter de nouveaux microcontrôleurs à l'analyse statique. Pour plus d'informations, consultez le moteur / * / arch /
Noyau de l'appareil AVR
Noyau de l'appareil AVRE
Avre + Core de l'appareil
Noyau de périphérique AVRXM
Noyau de périphérique AVRXT
Noyau de l'appareil AVRRC
désassembleur
Références croisées (xref-from, xref-to)
drapeaux d'analyseur
Décomposer et classer les instructions
Analyseur pour les binaires AVR
lecteur de format
Interrompre le support
Cycle de simulation précise en temps réel
Prise en charge de 133 instructions d'assemblage AVR
Simulation précise des périphériques internes
Actuellement, VMCU prend en charge: ~ 133 instructions. Quelques instructions sont implémentées en tant qu'instructions «NOP», par conséquent, n'ont pas de fonctionnalité réelle. Ces instructions seront mises en œuvre dès que possible. Les instructions suivantes nécessitent un travail supplémentaire:
Toutes les autres instructions d'assemblage fonctionnent très bien.
libvmcu a des liaisons Java pour les fonctionnalités de base. Pour plus d'informations, jetez un œil aux liaisons / java /
Notez également que les liaisons peuvent ne pas toujours fonctionner avec la dernière version en raison du développement du moteur.
| Moteur | Conducteurs | Reliures | Essai |
|---|---|---|---|
| fermé pour les relations publiques | Ouvert pour PR | Ouvert pour PR | Ouvert pour PR |
Au moment de la rédaction de cela, la documentation est toujours en développement. La documentation (incomplète) peut être trouvée sur https://github.com/milo-d/libvmcu-virtual-mcu-bibrary/wiki
Si vous manquez des informations et ne souhaitez pas attendre le wiki, les fichiers d'en-tête libvmcu sont également bien documentés.