Update:
I have written a tool to disassemble EV3 programs. The EV3 software compiles the .ev3
file to a .rbf
file and sends that to the EV3 brick. The disassembler can convert the .rbf
file into a .lms
file, which is a sort of assembly language that can be used to create programs for the EV3.
Here is a simple example using a trivial .ev3
project.
To create the .rbf
file, we have to download the program to an EV3 brick. Then we can upload the .rbf
file from the brick using the Memory Browser.
Running the disassembler on the .rbf
file will result in this:
// Disassembly of C:\Users\david\Desktop\Program.rbf
//
// Byte code version: 0.57
DATA8 GLOBAL0
DATA8 GLOBAL1
DATA8 GLOBAL2
DATA8 GLOBAL3
DATA8 GLOBAL4
DATA8 GLOBAL5
DATA8 GLOBAL6
DATA8 GLOBAL7
DATA8 GLOBAL8
DATA8 GLOBAL9
DATA8 GLOBAL10
DATA8 GLOBAL11
DATA8 GLOBAL12
DATA8 GLOBAL13
DATA8 GLOBAL14
DATA8 GLOBAL15
DATA8 GLOBAL16
DATA8 GLOBAL17
DATA8 GLOBAL18
DATA8 GLOBAL19
DATA8 GLOBAL20
vmthread OBJECT1
{
DATA8 LOCAL0
DATA8 LOCAL1
DATA8 LOCAL2
DATA8 LOCAL3
DATA8 LOCAL4
OFFSET1_0:
OUTPUT_RESET(0,15)
OFFSET1_3:
INPUT_DEVICE(CLR_ALL,-1)
OFFSET1_6:
MOVE32_32(0,LOCAL0)
OFFSET1_9:
ADD32(GLOBAL12,1,GLOBAL12)
OFFSET1_13:
MOVE8_8(GLOBAL20,LOCAL4)
OFFSET1_16:
ADD32(GLOBAL8,1,GLOBAL8)
OFFSET1_20:
JR_FALSE(LOCAL4,OFFSET1_29)
OFFSET1_23:
ADD32(LOCAL0,1,LOCAL0)
OFFSET1_27:
JR(OFFSET1_9)
OFFSET1_29:
ADD32(GLOBAL4,1,GLOBAL4)
OFFSET1_33:
CALL(OBJECT2,1123418112,0,1117126656,1065353216,0,1)
OFFSET1_58:
ADD32(GLOBAL0,1,GLOBAL0)
}
subcall OBJECT2
{
IN_F LOCAL0
IN_F LOCAL4
IN_F LOCAL8
IN_F LOCAL12
IN_32 LOCAL16
IN_8 LOCAL20
DATA8 LOCAL21
DATA8 LOCAL22
DATA8 LOCAL23
DATA8 LOCAL24
DATA8 LOCAL25
DATA8 LOCAL26
DATA8 LOCAL27
DATA8 LOCAL28
DATA8 LOCAL29
DATA8 LOCAL30
DATA8 LOCAL31
DATA8 LOCAL32
DATA8 LOCAL33
DATA8 LOCAL34
DATA8 LOCAL35
DATA8 LOCAL36
DATA8 LOCAL37
DATA8 LOCAL38
DATA8 LOCAL39
DATA8 LOCAL40
DATA8 LOCAL41
DATA8 LOCAL42
DATA8 LOCAL43
DATA8 LOCAL44
DATA8 LOCAL45
DATA8 LOCAL46
DATA8 LOCAL47
DATA8 LOCAL48
DATA8 LOCAL49
DATA8 LOCAL50
DATA8 LOCAL51
DATA8 LOCAL52
DATA8 LOCAL53
DATA8 LOCAL54
DATA8 LOCAL55
DATA8 LOCAL56
DATA8 LOCAL57
DATA8 LOCAL58
DATA8 LOCAL59
DATA8 LOCAL60
DATA8 LOCAL61
DATA8 LOCAL62
DATA8 LOCAL63
DATA8 LOCAL64
DATA8 LOCAL65
DATA8 LOCAL66
OFFSET2_7:
CP_EQF(LOCAL12,0,LOCAL66)
OFFSET2_12:
MOVE32_32(GLOBAL16,LOCAL36)
OFFSET2_16:
AND32(LOCAL16,LOCAL36,LOCAL48)
OFFSET2_22:
CP_GT32(LOCAL48,0,LOCAL65)
OFFSET2_28:
OR8(LOCAL66,LOCAL65,LOCAL64)
OFFSET2_35:
JR_EQ8(LOCAL64,1,OFFSET2_45)
OFFSET2_40:
JR_EQ8(LOCAL64,0,OFFSET2_48)
OFFSET2_45:
JR(OFFSET2_139)
OFFSET2_48:
MULF(LOCAL12,360.0F,LOCAL24)
OFFSET2_56:
CALL(OBJECT3,LOCAL0,LOCAL8,LOCAL24,LOCAL4,LOCAL58,LOCAL60,LOCAL20)
OFFSET2_68:
MOVE32_32(LOCAL16,LOCAL52)
OFFSET2_72:
MOVE8_8(LOCAL60,LOCAL59)
OFFSET2_77:
MOVE8_8(LOCAL58,LOCAL57)
OFFSET2_82:
MOVE32_32(0,LOCAL44)
OFFSET2_86:
MOVE32_32(GLOBAL16,LOCAL40)
OFFSET2_90:
AND32(LOCAL52,LOCAL40,LOCAL32)
OFFSET2_97:
CP_GT32(LOCAL32,0,LOCAL62)
OFFSET2_103:
OUTPUT_TEST(LOCAL57,LOCAL59,LOCAL56)
OFFSET2_110:
CP_EQ8(LOCAL56,0,LOCAL61)
OFFSET2_116:
OR8(LOCAL61,LOCAL62,LOCAL63)
OFFSET2_123:
SLEEP()
OFFSET2_124:
JR_TRUE(LOCAL63,OFFSET2_137)
OFFSET2_128:
ADD32(LOCAL44,1,LOCAL44)
OFFSET2_134:
JR(OFFSET2_86)
OFFSET2_137:
JR(OFFSET2_139)
OFFSET2_139:
}
subcall OBJECT3
{
IN_F LOCAL0
IN_F LOCAL4
IN_F LOCAL8
IN_F LOCAL12
OUT_8 LOCAL16
OUT_8 LOCAL17
IN_8 LOCAL18
DATA8 LOCAL19
DATA8 LOCAL20
DATA8 LOCAL21
DATA8 LOCAL22
DATA8 LOCAL23
DATA8 LOCAL24
DATA8 LOCAL25
DATA8 LOCAL26
DATA8 LOCAL27
DATA8 LOCAL28
DATA8 LOCAL29
DATA8 LOCAL30
DATA8 LOCAL31
DATA8 LOCAL32
DATA8 LOCAL33
DATA8 LOCAL34
DATA8 LOCAL35
DATA8 LOCAL36
DATA8 LOCAL37
DATA8 LOCAL38
DATA8 LOCAL39
DATA8 LOCAL40
DATA8 LOCAL41
DATA8 LOCAL42
DATA8 LOCAL43
DATA8 LOCAL44
DATA8 LOCAL45
DATA8 LOCAL46
DATA8 LOCAL47
DATA8 LOCAL48
DATA8 LOCAL49
DATA8 LOCAL50
DATA8 LOCAL51
DATA8 LOCAL52
DATA8 LOCAL53
DATA8 LOCAL54
DATA8 LOCAL55
DATA8 LOCAL56
DATA8 LOCAL57
DATA8 LOCAL58
DATA8 LOCAL59
DATA8 LOCAL60
DATA8 LOCAL61
DATA8 LOCAL62
DATA8 LOCAL63
DATA8 LOCAL64
DATA8 LOCAL65
DATA8 LOCAL66
DATA8 LOCAL67
DATA8 LOCAL68
DATA8 LOCAL69
DATA8 LOCAL70
DATA8 LOCAL71
DATA8 LOCAL72
DATA8 LOCAL73
DATA8 LOCAL74
DATA8 LOCAL75
DATA8 LOCAL76
DATA8 LOCAL77
DATA8 LOCAL78
DATA8 LOCAL79
DATA8 LOCAL80
DATA8 LOCAL81
DATA8 LOCAL82
DATA8 LOCAL83
DATA8 LOCAL84
DATA8 LOCAL85
DATA8 LOCAL86
DATA8 LOCAL87
DATA8 LOCAL88
DATA8 LOCAL89
DATA8 LOCAL90
DATA8 LOCAL91
DATA8 LOCAL92
DATA8 LOCAL93
DATA8 LOCAL94
DATA8 LOCAL95
DATA8 LOCAL96
DATA8 LOCAL97
DATA8 LOCAL98
DATA8 LOCAL99
DATA8 LOCAL100
DATA8 LOCAL101
DATA8 LOCAL102
DATA8 LOCAL103
DATA8 LOCAL104
DATA8 LOCAL105
OFFSET3_8:
CP_LTF(LOCAL8,0,LOCAL100)
OFFSET3_13:
JR_EQ8(LOCAL100,1,OFFSET3_24)
OFFSET3_18:
MOVEF_F(LOCAL4,LOCAL56)
OFFSET3_22:
JR(OFFSET3_40)
OFFSET3_24:
SUBF(0.0F,LOCAL4,LOCAL72)
OFFSET3_33:
MOVEF_F(LOCAL72,LOCAL56)
OFFSET3_38:
JR(OFFSET3_40)
OFFSET3_40:
MOVEF_8(LOCAL56,LOCAL97)
OFFSET3_45:
CP_NEQF(LOCAL56,0,LOCAL101)
OFFSET3_51:
MATH(ABS,LOCAL8,LOCAL68)
OFFSET3_56:
MOVEF_32(LOCAL68,LOCAL88)
OFFSET3_61:
MOVEF_F(2.0F,LOCAL32)
OFFSET3_69:
MOVEF_32(LOCAL0,LOCAL84)
OFFSET3_73:
PORT_CNV_OUTPUT(LOCAL84,LOCAL99,LOCAL98,LOCAL104)
OFFSET3_82:
MOVE8_8(LOCAL98,LOCAL17)
OFFSET3_86:
MOVE8_8(LOCAL99,LOCAL16)
OFFSET3_90:
AND8(LOCAL101,LOCAL18,LOCAL103)
OFFSET3_96:
MOVE16_16(0,LOCAL92)
OFFSET3_100:
JR_FALSE(LOCAL103,OFFSET3_108)
OFFSET3_104:
MOVE16_16(1,LOCAL92)
OFFSET3_108:
MOVE16_8(LOCAL92,LOCAL96)
OFFSET3_113:
MOVEF_F(LOCAL12,LOCAL40)
OFFSET3_117:
MOVEF_F(-100.0F,LOCAL36)
OFFSET3_125:
MOVEF_F(LOCAL40,LOCAL44)
OFFSET3_130:
MOVEF_F(100.0F,LOCAL52)
OFFSET3_138:
CP_GTF(LOCAL44,LOCAL52,LOCAL102)
OFFSET3_145:
MOVEF_F(LOCAL44,LOCAL48)
OFFSET3_150:
JR_FALSE(LOCAL102,OFFSET3_159)
OFFSET3_154:
MOVEF_F(LOCAL52,LOCAL48)
OFFSET3_159:
CP_LTF(LOCAL48,LOCAL36,LOCAL105)
OFFSET3_166:
MOVEF_F(LOCAL48,LOCAL24)
OFFSET3_170:
JR_FALSE(LOCAL105,OFFSET3_178)
OFFSET3_174:
MOVEF_F(LOCAL36,LOCAL24)
OFFSET3_178:
MOVEF_F(LOCAL24,LOCAL20)
OFFSET3_181:
MULF(LOCAL20,LOCAL32,LOCAL28)
OFFSET3_186:
JR_EQ8(LOCAL104,1,OFFSET3_197)
OFFSET3_191:
MOVEF_F(LOCAL28,LOCAL60)
OFFSET3_195:
JR(OFFSET3_218)
OFFSET3_197:
MOVEF_F(0.0F,LOCAL76)
OFFSET3_205:
SUBF(LOCAL76,LOCAL28,LOCAL64)
OFFSET3_211:
MOVEF_F(LOCAL64,LOCAL60)
OFFSET3_216:
JR(OFFSET3_218)
OFFSET3_218:
MOVEF_16(LOCAL60,LOCAL94)
OFFSET3_223:
OUTPUT_STEP_SYNC(LOCAL99,LOCAL98,LOCAL97,LOCAL94,LOCAL88,LOCAL96)
OFFSET3_236:
}
Being a disassembly, this can be a bit hard to interpret since there are not any helpful variable names. You can find information on EV3 assembly language here.
Original answer:
The .ev3
file is actually just a zip file. You can use any zip utility to browse the contents or unzip it. It will look something like this:
├── Activity.x3a
├── ActivityAssets.laz
├── Program.ev3p
├── Project.lvprojx
├── ___CopyrightYear
└── ___ProjectTitle
The ___*
files are just plain text files, ActivityAssets.laz
is another zip file and the rest are xml files.