├── .clang-format ├── .github └── workflows │ ├── ci.yaml │ └── linter.yml ├── .gitignore ├── .reuse └── dep5 ├── LICENSES └── LGPL-3.0-only.txt ├── README.md ├── example └── cm7.bin ├── include ├── simatic.h └── simatic_types.h ├── meson.build ├── meson_options.txt ├── src ├── plugin_analysis.c ├── plugin_asm.c ├── plugin_bin.c └── simatic.c └── unit └── test_simatic.c /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | MaxEmptyLinesToKeep: 1 3 | SpaceBeforeParens: ControlStatements 4 | SpaceInEmptyParentheses: false 5 | SpacesInContainerLiterals: true 6 | BasedOnStyle: LLVM 7 | ContinuationIndentWidth: 8 8 | IndentCaseLabels: false 9 | IndentFunctionDeclarationAfterType: false 10 | IndentWidth: 8 11 | UseTab: ForContinuationAndIndentation 12 | ColumnLimit: 0 13 | BreakBeforeBraces: Attach 14 | BreakBeforeTernaryOperators: true 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortCaseLabelsOnASingleLine: true 17 | AllowShortFunctionsOnASingleLine: Inline 18 | AllowShortLoopsOnASingleLine: false 19 | AlignAfterOpenBracket: DontAlign 20 | AlignEscapedNewlines: DontAlign 21 | AlignConsecutiveMacros: true 22 | AlignTrailingComments: false 23 | AlignOperands: false 24 | Cpp11BracedListStyle: false 25 | ForEachMacros: ['rz_list_foreach', 'rz_list_foreach_safe', 'rz_pvector_foreach', 'rz_rbtree_foreach', 'rz_interval_tree_foreach', 'ls_foreach', 'rz_skiplist_foreach', 'graph_foreach_anode'] 26 | SortIncludes: false 27 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: "Run tests" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | Normal: 11 | runs-on: ubuntu-20.04 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v2 15 | - name: Install meson and ninja 16 | run: pip3 install --user meson ninja 17 | - name: Run Unit Tests 18 | run: | 19 | export PATH=${HOME}/Library/Python/3.8/bin:${HOME}/Library/Python/3.9/bin:${HOME}/.local/bin:${PATH} 20 | meson -Dbuildtype=release -Dbuild_shared_libs=false build 21 | ninja -C build test 22 | 23 | Asan: 24 | runs-on: ubuntu-20.04 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@v2 28 | - name: Install meson and ninja 29 | run: pip3 install --user meson ninja 30 | - name: Run Unit Tests with ASAN 31 | env: 32 | ASAN_OPTIONS: detect_leaks=0,detect_odr_violation=0,allocator_may_return_null=1 33 | run: | 34 | export PATH=${HOME}/Library/Python/3.8/bin:${HOME}/Library/Python/3.9/bin:${HOME}/.local/bin:${PATH} 35 | meson -Dbuildtype=debugoptimized -Dbuild_shared_libs=false -Db_sanitize=address,undefined build 36 | ninja -C build test 37 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | name: "Licenses reuse lint" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | licenses: 11 | runs-on: ubuntu-20.04 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v2 15 | - name: REUSE Compliance Check 16 | uses: fsfe/reuse-action@v1.1 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | testsuite 3 | r2-simatic-s7/*.so 4 | r2-simatic-s7/*.o 5 | build* -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: Rizin 3 | Upstream-Contact: RizinOrg 4 | Source: https://github.com/rizinorg/rizin 5 | 6 | Files: .github/** example/** 7 | Copyright: 2021 RizinOrg 8 | License: LGPL-3.0-only 9 | 10 | Files: .clang-format 11 | Copyright: 2020 RizinOrg 12 | License: LGPL-3.0-only 13 | 14 | Files: .gitignore 15 | Copyright: 2021 RizinOrg 16 | License: LGPL-3.0-only 17 | 18 | Files: meson.build 19 | Copyright: 2021 RizinOrg 20 | License: LGPL-3.0-only 21 | 22 | Files: meson_options.txt 23 | Copyright: 2020 RizinOrg 24 | License: LGPL-3.0-only 25 | 26 | Files: *.md 27 | Copyright: 2021 RizinOrg 28 | License: LGPL-3.0-only 29 | -------------------------------------------------------------------------------- /LICENSES/LGPL-3.0-only.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | 6 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 7 | 8 | This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 9 | 10 | 0. Additional Definitions. 11 | 12 | As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. 13 | 14 | "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. 15 | 16 | An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. 17 | 18 | A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". 19 | 20 | The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. 21 | 22 | The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 23 | 24 | 1. Exception to Section 3 of the GNU GPL. 25 | You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 26 | 27 | 2. Conveying Modified Versions. 28 | If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: 29 | 30 | a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or 31 | 32 | b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 33 | 34 | 3. Object Code Incorporating Material from Library Header Files. 35 | The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: 36 | 37 | a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. 38 | 39 | b) Accompany the object code with a copy of the GNU GPL and this license document. 40 | 41 | 4. Combined Works. 42 | You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: 43 | 44 | a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. 45 | 46 | b) Accompany the Combined Work with a copy of the GNU GPL and this license document. 47 | 48 | c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. 49 | 50 | d) Do one of the following: 51 | 52 | 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 53 | 54 | 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. 55 | 56 | e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 57 | 58 | 5. Combined Libraries. 59 | You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: 60 | 61 | a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. 62 | 63 | b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 64 | 65 | 6. Revised Versions of the GNU Lesser General Public License. 66 | The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. 67 | 68 | Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. 69 | 70 | If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall 71 | apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rizin MC7 disassembler 2 | 3 | Library to disassemble MC7 bytecode for Siemens PLC SIMATIC S7-300 and S7-400 4 | 5 | **please report any bug. this is experimental for now** 6 | 7 | ## Install 8 | 9 | ```bash 10 | meson build 11 | ninja -C build 12 | sudo ninja -C build install 13 | ``` 14 | 15 | ## Usage 16 | 17 | ``` 18 | $ rizin sample.mc7.bin 19 | [0x00000000]> e asm.arch = mc7 20 | [0x00000000]> pdi 5 @ 0x24 21 | 0x00000024 600d +D 22 | 0x00000026 6009 -D 23 | 0x00000028 600a *D 24 | 0x0000002a 600e /D 25 | 0x0000002c 6001 MOD 26 | ``` 27 | -------------------------------------------------------------------------------- /example/cm7.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rizinorg/rz-libmc7/17814af7176b2d5f04ce581925d2d97d9bee9ce4/example/cm7.bin -------------------------------------------------------------------------------- /include/simatic.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019-2022 deroad 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | #ifndef LIB_SIMATIC_H 5 | #define LIB_SIMATIC_H 6 | 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | #define S7_INSTRUCTION_LEN 128 14 | 15 | typedef struct s7_instr_t { 16 | char assembly[S7_INSTRUCTION_LEN]; 17 | ut64_t jump; 18 | bool_t is_return; 19 | } S7Instr; 20 | 21 | int simatic_s7_decode_instruction(const ut8_t *buffer, const ut64_t size, const ut64_t addr, S7Instr *instr); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | #endif /* LIB_SIMATIC_H */ -------------------------------------------------------------------------------- /include/simatic_types.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019-2022 deroad 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | #ifndef LIB_SIMATIC_TYPES_H 5 | #define LIB_SIMATIC_TYPES_H 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | #define bool_t int 12 | #define st8_t signed char 13 | #define st16_t short 14 | #define st32_t int 15 | #define st64_t long long 16 | #define ut8_t unsigned char 17 | #define ut16_t unsigned short 18 | #define ut32_t unsigned int 19 | #define ut64_t unsigned long long 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | 25 | #endif /* LIB_SIMATIC_TYPES_H */ -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('libmc7', 'c', 2 | version: 'v0.4.0', 3 | license: 'LGPL3', 4 | meson_version: '>=0.55.0', 5 | default_options: [ 6 | 'buildtype=debugoptimized', 7 | 'b_vscrt=from_buildtype', 8 | ]) 9 | 10 | 11 | libmc7_deps = [] 12 | libmc7_incs = ['.', 'src','include'] 13 | 14 | if get_option('build_shared_libs') 15 | rizin = find_program('rizin', required: false) 16 | rz_core_dep = dependency('rz_core') 17 | libmc7_deps += rz_core_dep 18 | libmc7_deps += dependency('rz_util') 19 | libmc7_deps += dependency('rz_cons') 20 | libmc7_deps += dependency('rz_config') 21 | libmc7_deps += dependency('rz_io') 22 | 23 | rizin_plugdir = '' 24 | if rizin_plugdir == '' 25 | rizin_plugdir = rz_core_dep.get_variable(pkgconfig: 'plugindir', cmake: 'rz_core_PLUGINDIR') 26 | plugin_libmc7_dir = join_paths(get_option('prefix'), rizin_plugdir, 'libmc7') 27 | else 28 | plugin_libmc7_dir = join_paths(rizin_plugdir, 'libmc7') 29 | endif 30 | message(' - ',plugin_libmc7_dir ) 31 | 32 | 33 | libmc7_c_args = [] 34 | libmc7_asm_src = [ 35 | 'src' / 'simatic.c', 36 | 'src' / 'plugin_asm.c', 37 | ] 38 | shared_library('libmc7_asm', libmc7_asm_src, 39 | c_args : libmc7_c_args, 40 | dependencies: libmc7_deps, 41 | include_directories: include_directories(libmc7_incs), 42 | implicit_include_directories: false, 43 | install: true, 44 | install_dir: rizin_plugdir 45 | ) 46 | libmc7_analysis_src = [ 47 | 'src' / 'simatic.c', 48 | 'src' / 'plugin_analysis.c', 49 | ] 50 | shared_library('libmc7_analysis', libmc7_analysis_src, 51 | c_args : libmc7_c_args, 52 | dependencies: libmc7_deps, 53 | include_directories: include_directories(libmc7_incs), 54 | implicit_include_directories: false, 55 | install: true, 56 | install_dir: rizin_plugdir 57 | ) 58 | libmc7_bin_src = [ 59 | 'src' / 'simatic.c', 60 | 'src' / 'plugin_bin.c', 61 | ] 62 | shared_library('libmc7_bin', libmc7_bin_src, 63 | c_args : libmc7_c_args, 64 | dependencies: libmc7_deps, 65 | include_directories: include_directories(libmc7_incs), 66 | implicit_include_directories: false, 67 | install: true, 68 | install_dir: rizin_plugdir 69 | ) 70 | endif 71 | 72 | libmc7_src = ['src' / 'simatic.c'] 73 | 74 | exe = executable('test_simatic', ['unit' / 'test_simatic.c'] + libmc7_src, 75 | c_args: [], 76 | include_directories: include_directories(libmc7_incs), 77 | dependencies: [], 78 | install: false, 79 | implicit_include_directories: false) 80 | 81 | test('test_simatic', exe) -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('build_shared_libs', type: 'boolean', value: true, description: 'enables or disables the rizin shared libraries') -------------------------------------------------------------------------------- /src/plugin_analysis.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 RizinOrg 2 | // SPDX-FileCopyrightText: 2019-2022 deroad 3 | // SPDX-License-Identifier: LGPL-3.0-only 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | static int s7_analysis(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask) { 12 | S7Instr instr = { 0 }; 13 | int read = simatic_s7_decode_instruction(data, len, addr, &instr); 14 | if (read > 0) { 15 | op->size = read; 16 | if (instr.jump != UT64_MAX) { 17 | op->type = RZ_ANALYSIS_OP_TYPE_CJMP; 18 | op->jump = instr.jump; 19 | op->fail = addr + op->size; 20 | } 21 | op->eob = instr.is_return; 22 | } 23 | return op->size; 24 | } 25 | 26 | static int s7_archinfo(RzAnalysis *a, RzAnalysisInfoType q) { 27 | switch (q) { 28 | case RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE: 29 | return 2; 30 | case RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE: 31 | return 6; 32 | case RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN: 33 | /* fall-thru */ 34 | case RZ_ANALYSIS_ARCHINFO_DATA_ALIGN: 35 | return 0; 36 | case RZ_ANALYSIS_ARCHINFO_CAN_USE_POINTERS: 37 | return true; 38 | default: 39 | return -1; 40 | } 41 | } 42 | 43 | RzAnalysisPlugin rz_analysis_plugin_mc7 = { 44 | .name = "mc7", 45 | .desc = "Simatic S7 analysis plugin", 46 | .arch = "mc7", 47 | .license = "LGPL3", 48 | .bits = 32, 49 | .archinfo = s7_archinfo, 50 | .op = &s7_analysis, 51 | }; 52 | 53 | #ifndef RZ_PLUGIN_INCORE 54 | RZ_API RzLibStruct rizin_plugin = { 55 | .type = RZ_LIB_TYPE_ANALYSIS, 56 | .data = &rz_analysis_plugin_mc7, 57 | .version = RZ_VERSION 58 | }; 59 | #endif 60 | -------------------------------------------------------------------------------- /src/plugin_asm.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 RizinOrg 2 | // SPDX-FileCopyrightText: 2019-2022 deroad 3 | // SPDX-License-Identifier: LGPL-3.0-only 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | static int disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) { 10 | S7Instr instr = { 0 }; 11 | int read = simatic_s7_decode_instruction(buf, len, a->pc, &instr); 12 | if (read < 0) { 13 | rz_asm_op_set_asm(op, "invalid"); 14 | op->size = 2; 15 | } else { 16 | rz_asm_op_set_asm(op, instr.assembly); 17 | op->size = read; 18 | } 19 | return op->size; 20 | } 21 | 22 | RzAsmPlugin rz_asm_plugin_simatic_mc7 = { 23 | .name = "mc7", 24 | .desc = "Simatic S7 disassembler", 25 | .license = "LGPL", 26 | .author = "deroad", 27 | .arch = "mc7", 28 | .cpus = "s7-300,s7-400", 29 | .bits = 32, 30 | .endian = RZ_SYS_ENDIAN_BIG, 31 | .disassemble = &disassemble, 32 | }; 33 | 34 | #ifndef RZ_PLUGIN_INCORE 35 | RZ_API RzLibStruct rizin_plugin = { 36 | .type = RZ_LIB_TYPE_ASM, 37 | .data = &rz_asm_plugin_simatic_mc7, 38 | .version = RZ_VERSION 39 | }; 40 | #endif -------------------------------------------------------------------------------- /src/plugin_bin.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 RizinOrg 2 | // SPDX-FileCopyrightText: 2019-2022 deroad 3 | // SPDX-License-Identifier: LGPL-3.0-only 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /** 12 | * This comes from the simulator. 13 | * 14 | * 0 1 2 3 4 5 6 7 8 9 a b c d e f 15 | * 00000000: 7070 0101 0108 0001 0000 0074 0000 0000 16 | * ~~~~ ++-- **.. &&&& :::: :::: ^^^^ ^^^^ 17 | * 00000010: 02ab 2735 2d03 03a1 6383 21a7 001c 0006 18 | * %%%% %%%% %%%% $$$$ $$$$ $$$$ ==== !!!! 19 | * 00000020: 0014 000a 20 | * @@@@ #### 21 | * 22 | * ~ block signature 23 | * + block version 24 | * - block attribute 25 | * * block language (STL: 0x01, LAD: 0x02, FBD: 0x03, SCL: 0x04, DB: 0x05, GRAPH: 0x06, SDB: 0x07) 26 | * . block type (OB: 0x08, DB: 0x0A, SDB: 0x0B, FC: 0x0C, SFC: 0x0D, FB: 0x0E, SFB: 0x0F) 27 | * & block number 28 | * : block size 29 | * ^ block password 30 | * % block last modified date 31 | * $ block interface last modified date 32 | * = block interface size 33 | * ! block segment table size 34 | * @ block local data size 35 | * # block data size 36 | */ 37 | 38 | typedef struct _mc7_block { 39 | ut16 signature; 40 | ut8 version; 41 | ut8 attribute; 42 | ut8 language; 43 | ut8 type; 44 | ut16 number; 45 | ut32 size; 46 | ut32 password; 47 | ut8 last_mod_date[6]; // last modified date 48 | ut8 iface_last_mod_date[6]; // last modified date 49 | ut16 iface_size; 50 | ut16 segment_size; 51 | ut16 local_data_size; 52 | ut16 data_size; 53 | } mc7_block_t; 54 | 55 | static ut16 read16(const ut8 *b) { 56 | ut16 a = b[1]; 57 | a |= (b[0] << 8); 58 | return a; 59 | } 60 | 61 | static ut32 read32(const ut8 *b) { 62 | ut32 a = read16(b); 63 | a |= read16(b + 2) << 16; 64 | return a; 65 | } 66 | 67 | static bool load_buffer(RzBinFile *bf, RzBinObject *bin_obj, RzBuffer *b, Sdb *sdb){ 68 | 69 | ut64 size; 70 | const ut8 *buf = rz_buf_data(b, &size); 71 | rz_return_val_if_fail(buf && size >= sizeof(mc7_block_t), false); 72 | mc7_block_t *blk = RZ_NEW0(mc7_block_t); 73 | if (!blk) { 74 | return false; 75 | } 76 | blk->signature = read16(buf); 77 | blk->version = buf[0x2]; 78 | blk->attribute = buf[0x3]; 79 | blk->language = buf[0x4]; 80 | blk->type = buf[0x5]; 81 | blk->number = read16(buf + 0x6); 82 | blk->size = read32(buf + 0x8); 83 | blk->password = read32(buf + 0xC); 84 | memcpy(blk->last_mod_date, buf + 0x10, 0x6); 85 | memcpy(blk->iface_last_mod_date, buf + 0x16, 0x6); 86 | blk->iface_size = read16(buf + 0x1C); 87 | blk->segment_size = read16(buf + 0x1E); 88 | blk->local_data_size = read16(buf + 0x20); 89 | blk->data_size = read16(buf + 0x22); 90 | bin_obj->bin_obj = (void *)blk; 91 | return true; 92 | } 93 | 94 | static void destroy(RzBinFile *bf) { 95 | free(bf->o->bin_obj); 96 | bf->o->bin_obj = NULL; 97 | return; 98 | } 99 | 100 | static ut64 baddr(RzBinFile *bf) { 101 | return 0; 102 | } 103 | 104 | static bool check_buffer(RzBuffer *b) { 105 | rz_return_val_if_fail(b, false); 106 | ut64 size; 107 | const ut8 *buf = rz_buf_data(b, &size); 108 | rz_return_val_if_fail(buf && size >= 2, false); 109 | return buf[0] == 0x70 && buf[1] == 0x70; 110 | } 111 | 112 | static RzBinInfo *info(RzBinFile *arch) { 113 | RzBinInfo *ret = RZ_NEW0(RzBinInfo); 114 | rz_return_val_if_fail(ret, NULL); 115 | 116 | if (!arch) { 117 | free(ret); 118 | return NULL; 119 | } 120 | ret->file = strdup(arch->file); 121 | ret->type = strdup("mc7"); 122 | ret->machine = strdup("Siemens Step7"); 123 | ret->arch = strdup("mc7"); 124 | ret->bits = 32; 125 | 126 | return ret; 127 | } 128 | 129 | static RzPVector *entries(RzBinFile *bf) { 130 | RzPVector *ret; 131 | RzBinAddr *ptr = NULL; 132 | if (!(ret = rz_pvector_new(NULL))) { 133 | return NULL; 134 | } 135 | if (!(ptr = RZ_NEW0(RzBinAddr))) { 136 | return ret; 137 | } 138 | ptr->paddr = sizeof(mc7_block_t); 139 | rz_pvector_push(ret, ptr); 140 | return ret; 141 | } 142 | 143 | struct rz_bin_plugin_t rz_bin_plugin_mc7 = { 144 | .name = "mc7", 145 | .desc = "Simatic S7 disassembler", 146 | .license = "LGPL", 147 | .get_sdb = NULL, 148 | .load_buffer = &load_buffer, 149 | .destroy = &destroy, 150 | .check_buffer = &check_buffer, 151 | .baddr = &baddr, 152 | .entries = &entries, 153 | .sections = NULL, 154 | .info = &info, 155 | }; 156 | 157 | #ifndef RZ_PLUGIN_INCORE 158 | RZ_API RzLibStruct radare_plugin = { 159 | .type = RZ_LIB_TYPE_BIN, 160 | .data = &rz_bin_plugin_mc7, 161 | .version = RZ_VERSION 162 | }; 163 | #endif 164 | -------------------------------------------------------------------------------- /src/simatic.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2019-2022 deroad 2 | // SPDX-License-Identifier: LGPL-3.0-only 3 | 4 | #include "simatic.h" 5 | #include 6 | #include 7 | 8 | #if __WINDOWS__ 9 | #define PFMT64x "I64x" 10 | #else 11 | #define PFMT64x "llx" 12 | #endif 13 | 14 | #define false 0 15 | #define true (!false) 16 | 17 | #define INSTR_MASK_N(x) ((x) & (0x0F)) 18 | #define INSTR_MASK_T(x) ((x) & (0x70)) 19 | #define INSTR_MASK_T_LOW(x) ((x) & (0x07)) 20 | 21 | #define INSTR_IS_BITLOGIC(x) ((x) >= (0x10) && (x) <= (0x67)) 22 | #define INSTR_IS_BITLOGIC_N(x) ((x) >= (0x90) && (x) <= (0xE7)) 23 | 24 | #define INSTR_IS_BITLOGIC_MEM(x) (INSTR_MASK_T_LOW((x)) != 0 && INSTR_MASK_T_LOW((x)) != 7 && (x) >= (0x31) && (x) <= (0x6E)) 25 | #define INSTR_IS_BITLOGIC_MEM_N(x) (INSTR_MASK_T_LOW((x)) != 0 && INSTR_MASK_T_LOW((x)) != 7 && (x) >= (0xB1) && (x) <= (0xEE)) 26 | #define INSTR_IS_BITLOGIC_MEM_IO(x) (((x)&0xF) >= (0x9)) 27 | 28 | #define INSTR_IS_79(x) ((x) >= (0x10) && (x) <= (0x6D)) 29 | #define INSTR_IS_79_N(x) ((x) >= (0x90) && (x) <= (0xED)) 30 | 31 | #define INSTR_IS_7E(x) ((x) >= (0x01) && (x) <= (0x67)) 32 | 33 | #define INSTR_IS_MEM(x) ((x) >= (0x30) && (x) <= (0x6E)) 34 | #define INSTR_IS_MEM_N(x) ((x) >= (0xB0) && (x) <= (0xEE)) 35 | #define INSTR_IS_MEM_IO(x) (((x)&0x0F) > (6)) 36 | 37 | #define S7_INVALID_JUMP (0xFFFFFFFFFFFFFFFFull) 38 | 39 | typedef float ft32; 40 | typedef double ft64; 41 | 42 | #define BIN_FMT "%c%c%c%c%c%c%c%c" 43 | #define BIN_BYTE(x) \ 44 | (((x)&0x80) ? '1' : '0'), \ 45 | (((x)&0x40) ? '1' : '0'), \ 46 | (((x)&0x20) ? '1' : '0'), \ 47 | (((x)&0x10) ? '1' : '0'), \ 48 | (((x)&0x08) ? '1' : '0'), \ 49 | (((x)&0x04) ? '1' : '0'), \ 50 | (((x)&0x02) ? '1' : '0'), \ 51 | (((x)&0x01) ? '1' : '0') 52 | 53 | typedef struct { 54 | const ut8_t byte; 55 | const char *type; 56 | } s7_type_t; 57 | 58 | static const s7_type_t types_def[] = { 59 | { 0x10, "I" }, 60 | { 0x20, "Q" }, 61 | { 0x30, "M" }, 62 | { 0x40, "DB" }, 63 | { 0x50, "DI" }, 64 | { 0x60, "L" }, 65 | { 0xFF, NULL } 66 | }; 67 | 68 | static const s7_type_t types_x[] = { 69 | { 0x10, "I" }, 70 | { 0x20, "Q" }, 71 | { 0x30, "M" }, 72 | { 0x40, "DBX" }, 73 | { 0x50, "DIX" }, 74 | { 0x60, "L" }, 75 | { 0xFF, NULL } 76 | }; 77 | 78 | static const s7_type_t types_w[] = { 79 | { 0x00, "PIW" }, 80 | { 0x10, "IW" }, 81 | { 0x20, "QW" }, 82 | { 0x30, "MW" }, 83 | { 0x40, "DBW" }, 84 | { 0x50, "DIW" }, 85 | { 0x60, "LW" }, 86 | { 0xFF, NULL } 87 | }; 88 | 89 | static const s7_type_t types_d[] = { 90 | { 0x00, "PID" }, 91 | { 0x10, "ID" }, 92 | { 0x20, "QD" }, 93 | { 0x30, "MD" }, 94 | { 0x40, "DBD" }, 95 | { 0x50, "DID" }, 96 | { 0x60, "LD" }, 97 | { 0xFF, NULL } 98 | }; 99 | 100 | static const s7_type_t types_b[] = { 101 | { 0x00, "PIB" }, 102 | { 0x10, "IB" }, 103 | { 0x20, "QB" }, 104 | { 0x30, "MB" }, 105 | { 0x40, "DBB" }, 106 | { 0x50, "DIB" }, 107 | { 0x60, "LB" }, 108 | { 0xFF, NULL } 109 | }; 110 | 111 | static inline const char *s7_type(ut8_t T, const s7_type_t *types) { 112 | while (types->type) { 113 | if (T == types->byte) { 114 | return types->type; 115 | } 116 | types++; 117 | } 118 | return "?"; 119 | } 120 | 121 | static inline const char *s7_mem_type(ut8_t T) { 122 | T = INSTR_MASK_T(T); 123 | return (T == 0x30 ? "MD" : (T == 0x40 ? "DBD" : (T == 0x50 ? "DID" : (T == 0x60 ? "LD" : NULL)))); 124 | } 125 | 126 | static inline ut16_t s7_ut16(const ut8_t *buffer) { 127 | return ((buffer[0] << 8) | buffer[1]); 128 | } 129 | 130 | static inline ut32_t s7_ut32(const ut8_t *buffer) { 131 | ut32_t x = ((buffer[0] << 24) | (buffer[1] << 16)); 132 | return x | ((buffer[2] << 8) | buffer[3]); 133 | } 134 | 135 | static inline void s7_print_bin32(const char *prefix, const ut8_t *buffer, S7Instr *instr) { 136 | char bin[34]; 137 | snprintf(bin, sizeof(bin), "" BIN_FMT "" BIN_FMT "" BIN_FMT "" BIN_FMT, BIN_BYTE(buffer[0]), BIN_BYTE(buffer[1]), BIN_BYTE(buffer[2]), BIN_BYTE(buffer[3])); 138 | ut64_t i; 139 | for (i = 0; i < 31; ++i) { 140 | if (bin[i] != '0') { 141 | break; 142 | } 143 | } 144 | snprintf(instr->assembly, sizeof(instr->assembly), "%s%s", prefix, &bin[i]); 145 | } 146 | 147 | static inline void s7_print_bin16(const char *prefix, const ut8_t *buffer, S7Instr *instr) { 148 | char bin[18]; 149 | snprintf(bin, sizeof(bin), "" BIN_FMT "" BIN_FMT, BIN_BYTE(buffer[0]), BIN_BYTE(buffer[1])); 150 | ut64_t i; 151 | for (i = 0; i < 15; ++i) { 152 | if (bin[i] != '0') { 153 | break; 154 | } 155 | } 156 | snprintf(instr->assembly, sizeof(instr->assembly), "%s%s", prefix, &bin[i]); 157 | } 158 | 159 | static int s7_decode_bitlogic(const char *zero_op, const char *memory_op, const char *io_op, const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 160 | if (buffer[0] == 0x00) { 161 | snprintf(instr->assembly, sizeof(instr->assembly), zero_op); 162 | return 2; 163 | } else if (size > 2) { 164 | if (INSTR_IS_BITLOGIC(buffer[0])) { 165 | ut16_t value = s7_ut16(buffer + 1); 166 | ut8_t N = INSTR_MASK_N(buffer[0]); 167 | // if (INSTR_MASK_T (buffer[0]) < 0x40 && value < 256) { 168 | // return -1; 169 | // } 170 | const char *type = s7_type(INSTR_MASK_T(buffer[0]), types_x); 171 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %s %u.%u", memory_op, type, value, N); 172 | return 4; 173 | } else if (io_op && INSTR_IS_BITLOGIC_N(buffer[0])) { // io_op might be NULL, because some might not have BITLOGIC_N 174 | ut16_t value = s7_ut16(buffer + 1); 175 | ut8_t N = INSTR_MASK_N(buffer[0]); 176 | // if (INSTR_MASK_T (buffer[0]) < 0x40 && value < 256) { 177 | // return -1; 178 | // } 179 | const char *type = s7_type(INSTR_MASK_T(buffer[0]), types_x); 180 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %s %u.%u", io_op, type, value, N); 181 | return 4; 182 | } 183 | } 184 | return -1; 185 | } 186 | 187 | static int s7_decode_byte(const char *op, const char *prefix, const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 188 | (void)size; 189 | ut8_t N = buffer[0]; 190 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %s%u", op, prefix, N); 191 | return 2; 192 | } 193 | 194 | static int s7_decode_byte_s(const char *op, const char *suffix, const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 195 | (void)size; 196 | ut8_t N = buffer[0]; 197 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %u%s", op, N, suffix); 198 | return 2; 199 | } 200 | 201 | static int s7_decode_4bit(const char *op, bool_t high, const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 202 | (void)size; 203 | ut8_t N = high ? (buffer[0] >> 4) : (buffer[0] & 0x0F); 204 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %u", op, N); 205 | return 2; 206 | } 207 | 208 | static int s7_decode_byte_signed(const char *op, const char *type_pos, const char *type_neg, const char *suffix, const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 209 | (void)size; 210 | ut8_t N = (ut8_t)buffer[0]; 211 | if (N > 0x7F) { 212 | N &= 0x7F; 213 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %s %u%s", op, type_neg, N, suffix); 214 | } else { 215 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %s %u%s", op, type_pos, N, suffix); 216 | } 217 | return 2; 218 | } 219 | 220 | static int s7_decode_cmp(const char *type, const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 221 | (void)size; 222 | switch (buffer[0]) { 223 | case 0x20: 224 | snprintf(instr->assembly, sizeof(instr->assembly), ">%s", type); 225 | break; 226 | case 0x40: 227 | snprintf(instr->assembly, sizeof(instr->assembly), "<%s", type); 228 | break; 229 | case 0x60: 230 | snprintf(instr->assembly, sizeof(instr->assembly), "<>%s", type); 231 | break; 232 | case 0x80: 233 | snprintf(instr->assembly, sizeof(instr->assembly), "==%s", type); 234 | break; 235 | case 0xA0: 236 | snprintf(instr->assembly, sizeof(instr->assembly), ">=%s", type); 237 | break; 238 | case 0xC0: 239 | snprintf(instr->assembly, sizeof(instr->assembly), "<=%s", type); 240 | break; 241 | default: 242 | return -1; 243 | } 244 | return 2; 245 | } 246 | 247 | static int s7_decode_lit16(const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 248 | if (size < 2) { 249 | return -1; 250 | } 251 | ut16_t value = s7_ut16(buffer + 1); 252 | switch (buffer[0]) { 253 | case 0x02: 254 | s7_print_bin16("L 2#", buffer + 1, instr); 255 | break; 256 | case 0x03: 257 | snprintf(instr->assembly, sizeof(instr->assembly), "L %d", ((st16_t)value)); 258 | break; 259 | case 0x05: 260 | if (buffer[1]) { 261 | snprintf(instr->assembly, sizeof(instr->assembly), "L '%c%c'", buffer[1], buffer[2]); 262 | } else { 263 | snprintf(instr->assembly, sizeof(instr->assembly), "L '%c'", buffer[2]); 264 | } 265 | break; 266 | case 0x06: 267 | snprintf(instr->assembly, sizeof(instr->assembly), "L B#(%02u, %02u)", buffer[1], buffer[2]); 268 | break; 269 | case 0x07: 270 | snprintf(instr->assembly, sizeof(instr->assembly), "L W#16#%x", value); 271 | break; 272 | case 0x08: 273 | if (value < 0x1000) { 274 | snprintf(instr->assembly, sizeof(instr->assembly), "L C#%x", value); 275 | } else { 276 | return -1; 277 | } 278 | break; 279 | case 0x0A: { 280 | // MIN L D#1990-01-01 | MAX L D#2168-12-31 281 | time_t rawtime = (value * 86400) + 631152000; 282 | struct tm *ptm = localtime(&rawtime); 283 | int year = 1900 + ptm->tm_year; 284 | int month = ptm->tm_mon + 1; 285 | int day = ptm->tm_mday; 286 | snprintf(instr->assembly, sizeof(instr->assembly), "L D#%d-%d-%d", year, month, day); 287 | } break; 288 | case 0x0C: { 289 | // S5T#0MS -> S5T#2H46M30S 290 | if ((value & 0xf000) > 0x3000 || value > 0x3999) { 291 | return -1; 292 | } 293 | st32_t ms = 0; 294 | st32_t secs = 0; 295 | st32_t mins = 0; 296 | st32_t hours = 0; 297 | /* S5TIME 298 | * [--yy aaaa bbbb cccc] 299 | * 15 0 300 | * yy = 00 -> 10 ms - 9 s 990 ms (time base 10 ms) 301 | * yy = 01 -> 100 ms - 1 min 39 s 900 ms (time base 100 ms) 302 | * yy = 10 -> 1 s - 16 min 39 s (time base 1 s) 303 | * yy = 11 -> 10 s - 2 hr 46 min 30 s (time base 10 s) 304 | * 0000aaaabbbbcccc is time value in binary-coded decimal format 305 | */ 306 | ms = (((value & 0x0F00) >> 8) * 100) + (((value & 0xF0) >> 4) * 10) + (value & 0x0F); 307 | if ((value & 0xf000) == 0x3000) { 308 | ms *= 10000; 309 | } else if ((value & 0xf000) == 0x2000) { 310 | ms *= 1000; 311 | } else if ((value & 0xf000) == 0x1000) { 312 | ms *= 100; 313 | } else { 314 | ms *= 10; 315 | } 316 | 317 | if (ms >= 3600000) { 318 | hours = ms / 3600000; 319 | ms -= (hours * 3600000); 320 | } 321 | 322 | if (ms >= 60000) { 323 | mins = ms / 60000; 324 | ms -= (mins * 60000); 325 | } 326 | 327 | if (ms >= 1000) { 328 | secs = ms / 1000; 329 | ms -= (secs * 1000); 330 | } 331 | 332 | int p = snprintf(instr->assembly, sizeof(instr->assembly), "L S5T#"); 333 | if (hours > 0) { 334 | p += snprintf(instr->assembly + p, sizeof(instr->assembly) - p, "%dH", hours); 335 | } 336 | if (mins > 0) { 337 | p += snprintf(instr->assembly + p, sizeof(instr->assembly) - p, "%dM", mins); 338 | } 339 | if (secs > 0) { 340 | p += snprintf(instr->assembly + p, sizeof(instr->assembly) - p, "%dS", secs); 341 | } 342 | if ((ms > 0 && ((value & 0xf000) < 0x2000)) || (hours < 1 && mins < 1 && secs < 1)) { 343 | snprintf(instr->assembly + p, sizeof(instr->assembly) - p, "%dMS", ms); 344 | } 345 | return 4; 346 | } break; 347 | default: 348 | return -1; 349 | } 350 | return 4; 351 | } 352 | 353 | static inline const char *s7_memory_loc(ut8_t byte) { 354 | /* 355 | 80h | PI/PQ | Periphery input/output 356 | 81h | I | Input 357 | 82h | Q | Output 358 | 83h | M | Bit memory 359 | 84h | DB | Data block 360 | 85h | DI | Instance data block 361 | 86h | L | Local Stack 362 | 87h | V | Previous Local Stack 363 | */ 364 | switch (byte) { 365 | case 0x00: return ""; 366 | case 0x80: return "PI/PQ"; 367 | case 0x81: return "I"; 368 | case 0x82: return "Q"; 369 | case 0x83: return "M"; 370 | case 0x84: return "DB"; 371 | case 0x85: return "DI"; 372 | case 0x86: return "L"; 373 | case 0x87: return "V"; 374 | default: 375 | // eprintf ("missing area 0x%02x (%u)\n", byte, byte); 376 | break; 377 | } 378 | return NULL; 379 | } 380 | 381 | static int s7_decode_lit32(const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 382 | if (size < 5) { 383 | return -1; 384 | } 385 | ut32_t value = s7_ut32(buffer + 1); 386 | switch (buffer[0]) { 387 | case 0x01: // REAL NUMBER 388 | { 389 | ft32 *f = (ft32 *)&value; 390 | snprintf(instr->assembly, sizeof(instr->assembly), "L %.6f", (*f)); 391 | } break; 392 | case 0x02: 393 | s7_print_bin32("L 2#", buffer + 1, instr); 394 | break; 395 | case 0x03: 396 | snprintf(instr->assembly, sizeof(instr->assembly), "L L#%d", ((st32_t)value)); 397 | break; 398 | case 0x04: { 399 | const char *loc = s7_memory_loc(buffer[1]); 400 | if (!loc || (buffer[2] & 0xF8)) { 401 | return -1; 402 | } 403 | ut8_t bit_addr = buffer[2] & 7; 404 | value &= 0xFFFF; 405 | snprintf(instr->assembly, sizeof(instr->assembly), "L P#%s%u.%u", loc, value, bit_addr); 406 | } break; 407 | case 0x05: 408 | if (buffer[1] && buffer[2] && buffer[3]) { 409 | snprintf(instr->assembly, sizeof(instr->assembly), "L '%c%c%c%c'", buffer[1], buffer[2], buffer[3], buffer[4]); 410 | } else if (buffer[2] && buffer[3]) { 411 | snprintf(instr->assembly, sizeof(instr->assembly), "L '%c%c%c'", buffer[2], buffer[3], buffer[4]); 412 | } else if (buffer[3]) { 413 | snprintf(instr->assembly, sizeof(instr->assembly), "L '%c%c'", buffer[3], buffer[4]); 414 | } else { 415 | snprintf(instr->assembly, sizeof(instr->assembly), "L '%c'", buffer[4]); 416 | } 417 | break; 418 | case 0x06: 419 | snprintf(instr->assembly, sizeof(instr->assembly), "L B#(%02u, %02u, %02u, %02u)", buffer[1], buffer[2], buffer[3], buffer[4]); 420 | break; 421 | case 0x07: 422 | snprintf(instr->assembly, sizeof(instr->assembly), "L DW#16#%x", value); 423 | break; 424 | case 0x09: 425 | snprintf(instr->assembly, sizeof(instr->assembly), "L T#%uMS", value); 426 | break; 427 | case 0x0B: { 428 | ut32_t ms = value % 1000; 429 | ut32_t tsecs = value / 1000; 430 | ut32_t secs = tsecs % 60; 431 | ut32_t mins = (tsecs / 60) % 60; 432 | ut32_t hours = (tsecs / 3600); 433 | snprintf(instr->assembly, sizeof(instr->assembly), "L TOD#%u:%u:%u.%u", hours, mins, secs, ms); 434 | } break; 435 | default: 436 | return -1; 437 | } 438 | return 6; 439 | } 440 | 441 | static int s7_decode_bitlogic_mem(const char *zero_op, bool_t zero_op_value, const char *memory_op, const char *io_op, const char *n_memory_op, const char *n_io_op, 442 | const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 443 | if (buffer[0] == 0x00 && !zero_op_value) { 444 | snprintf(instr->assembly, sizeof(instr->assembly), zero_op); 445 | return 2; 446 | } else if (size > 2) { 447 | if (buffer[0] == 0x00 && zero_op_value) { 448 | st16_t value = (st16_t)s7_ut16(buffer + 1); 449 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %d", zero_op, value); 450 | return 4; 451 | } 452 | const char *mem_type = s7_mem_type(buffer[0]); 453 | ut16_t value = s7_ut16(buffer + 1); 454 | if (mem_type && INSTR_IS_BITLOGIC_MEM(buffer[0])) { 455 | const char *op = INSTR_IS_BITLOGIC_MEM_IO(buffer[0]) ? io_op : memory_op; 456 | const char *type = s7_type(INSTR_MASK_T(buffer[0] << 4), types_x); 457 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %s [%s %u]", op, type, mem_type, value); 458 | return 4; 459 | } else if (mem_type && INSTR_IS_BITLOGIC_MEM_N(buffer[0])) { 460 | const char *op = INSTR_IS_BITLOGIC_MEM_IO(buffer[0]) ? n_io_op : n_memory_op; 461 | if (!op) { 462 | return -1; 463 | } 464 | const char *type = s7_type(INSTR_MASK_T(buffer[0] << 4), types_x); 465 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %s [%s %u]", op, type, mem_type, value); 466 | return 4; 467 | } 468 | } 469 | return -1; 470 | } 471 | 472 | static int s7_decode_jump(const char *op, ut64_t addr, const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 473 | if (size > 2) { 474 | st16_t N = (st16_t)s7_ut16(buffer + 1); 475 | addr += N; 476 | instr->jump = addr; 477 | snprintf(instr->assembly, sizeof(instr->assembly), "%s 0x%" PFMT64x, op, addr); 478 | return 4; 479 | } 480 | return -1; 481 | } 482 | 483 | typedef struct { 484 | ut8_t byte; 485 | const char *op; 486 | } s7_static_t; 487 | 488 | static int s7_decode_static(const s7_static_t *s, const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 489 | (void)size; 490 | while (s && s->op) { 491 | if (buffer[0] == s->byte) { 492 | snprintf(instr->assembly, sizeof(instr->assembly), "%s", s->op); 493 | return 2; 494 | } 495 | s++; 496 | } 497 | return -1; 498 | } 499 | 500 | static int s7_decode_79(const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 501 | if (buffer[0] == 0x00) { 502 | snprintf(instr->assembly, sizeof(instr->assembly), "+I"); 503 | return 2; 504 | } else if (size > 2) { 505 | ut8_t op = buffer[0] & 0x07; 506 | ut8_t ar = (buffer[0] & 0x08) ? 2 : 1; 507 | ut16_t value = s7_ut16(buffer + 1); 508 | const char *type = s7_type(INSTR_MASK_T(buffer[0]), types_x); 509 | if (INSTR_IS_79(buffer[0])) { 510 | switch (op) { 511 | case 0x00: 512 | snprintf(instr->assembly, sizeof(instr->assembly), "A %s [AR%d, P#%u.%u]", type, ar, (value >> 3), (value & 7)); 513 | return 4; 514 | case 0x01: 515 | snprintf(instr->assembly, sizeof(instr->assembly), "AN %s [AR%d, P#%u.%u]", type, ar, (value >> 3), (value & 7)); 516 | return 4; 517 | case 0x02: 518 | snprintf(instr->assembly, sizeof(instr->assembly), "O %s [AR%d, P#%u.%u]", type, ar, (value >> 3), (value & 7)); 519 | return 4; 520 | case 0x03: 521 | snprintf(instr->assembly, sizeof(instr->assembly), "ON %s [AR%d, P#%u.%u]", type, ar, (value >> 3), (value & 7)); 522 | return 4; 523 | case 0x04: 524 | snprintf(instr->assembly, sizeof(instr->assembly), "X %s [AR%d, P#%u.%u]", type, ar, (value >> 3), (value & 7)); 525 | return 4; 526 | case 0x05: 527 | snprintf(instr->assembly, sizeof(instr->assembly), "XN %s [AR%d, P#%u.%u]", type, ar, (value >> 3), (value & 7)); 528 | return 4; 529 | default: 530 | return -1; 531 | } 532 | } else if (INSTR_IS_79_N(buffer[0])) { 533 | switch (op) { 534 | case 0x00: 535 | snprintf(instr->assembly, sizeof(instr->assembly), "S %s [AR%d, P#%u.%u]", type, ar, (value >> 3), (value & 7)); 536 | return 4; 537 | case 0x01: 538 | snprintf(instr->assembly, sizeof(instr->assembly), "R %s [AR%d, P#%u.%u]", type, ar, (value >> 3), (value & 7)); 539 | return 4; 540 | case 0x02: 541 | snprintf(instr->assembly, sizeof(instr->assembly), "= %s [AR%d, P#%u.%u]", type, ar, (value >> 3), (value & 7)); 542 | return 4; 543 | case 0x04: 544 | snprintf(instr->assembly, sizeof(instr->assembly), "FP %s [AR%d, P#%u.%u]", type, ar, (value >> 3), (value & 7)); 545 | return 4; 546 | case 0x05: 547 | snprintf(instr->assembly, sizeof(instr->assembly), "FN %s [AR%d, P#%u.%u]", type, ar, (value >> 3), (value & 7)); 548 | return 4; 549 | default: 550 | return -1; 551 | } 552 | } 553 | } 554 | return -1; 555 | } 556 | 557 | static inline const char *s7_type_7E(ut8_t T) { 558 | if (INSTR_MASK_T(T) == 0x00) { 559 | return INSTR_MASK_T_LOW(T) > 0x03 ? "PQ" : "PI"; 560 | } 561 | T = INSTR_MASK_T(T); 562 | return (T == 0x10 ? "I" : (T == 0x20 ? "Q" : (T == 0x30 ? "M" : (T == 0x40 ? "DB" : (T == 0x50 ? "DI" : (T == 0x60 ? "L" : "?")))))); 563 | } 564 | 565 | static int s7_decode_7E(const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 566 | if (size > 2 && INSTR_IS_7E(buffer[0])) { 567 | ut8_t op = buffer[0] & 0x07; 568 | ut16_t value = s7_ut16(buffer + 1); 569 | const char *type = s7_type_7E(buffer[0]); 570 | switch (op) { 571 | case 0x01: 572 | snprintf(instr->assembly, sizeof(instr->assembly), "L %sB %u", type, value); 573 | return 4; 574 | case 0x02: 575 | snprintf(instr->assembly, sizeof(instr->assembly), "L %sW %u", type, value); 576 | return 4; 577 | case 0x03: 578 | snprintf(instr->assembly, sizeof(instr->assembly), "L %sD %u", type, value); 579 | return 4; 580 | case 0x05: 581 | snprintf(instr->assembly, sizeof(instr->assembly), "T %sB %u", type, value); 582 | return 4; 583 | case 0x06: 584 | snprintf(instr->assembly, sizeof(instr->assembly), "T %sW %u", type, value); 585 | return 4; 586 | case 0x07: 587 | snprintf(instr->assembly, sizeof(instr->assembly), "T %sD %u", type, value); 588 | return 4; 589 | default: 590 | return -1; 591 | } 592 | } 593 | return -1; 594 | } 595 | 596 | static int s7_decode_mem(const char *zero_op, const char *memory_op, const char *io_op, const s7_type_t *memory_type, const s7_type_t *io_type, const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 597 | if (buffer[0] == 0x00) { 598 | snprintf(instr->assembly, sizeof(instr->assembly), zero_op); 599 | return 2; 600 | } else if (size > 2) { 601 | const char *mem_type = s7_mem_type(buffer[0]); 602 | ut16_t value = s7_ut16(buffer + 1); 603 | if (mem_type && INSTR_IS_MEM(buffer[0])) { 604 | const char *type = s7_type(INSTR_MASK_T(buffer[0] << 4), INSTR_IS_MEM_IO(buffer[0]) ? io_type : memory_type); 605 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %s [%s %u]", memory_op, type, mem_type, value); 606 | return 4; 607 | } else if (mem_type && INSTR_IS_MEM_N(buffer[0])) { 608 | const char *type = s7_type(INSTR_MASK_T(buffer[0] << 4), INSTR_IS_MEM_IO(buffer[0]) ? io_type : memory_type); 609 | snprintf(instr->assembly, sizeof(instr->assembly), "%s %s [%s %u]", io_op, type, mem_type, value); 610 | return 4; 611 | } 612 | } 613 | return -1; 614 | } 615 | 616 | static int s7_decode_BE(const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 617 | if (size > 2 && buffer[0] >= 0x11 && buffer[0] <= 0x6F && (buffer[0] & 0x0F)) { 618 | ut8_t op = buffer[0] & 0x0F; 619 | ut16_t value = s7_ut16(buffer + 1); 620 | const char *type = s7_type(INSTR_MASK_T(buffer[0]), types_def); 621 | switch (op) { 622 | case 0x01: 623 | snprintf(instr->assembly, sizeof(instr->assembly), "L %sB [AR1, P#%u.%u]", type, (value >> 3), (value & 7)); 624 | return 4; 625 | case 0x02: 626 | snprintf(instr->assembly, sizeof(instr->assembly), "L %sW [AR1, P#%u.%u]", type, (value >> 3), (value & 7)); 627 | return 4; 628 | case 0x03: 629 | snprintf(instr->assembly, sizeof(instr->assembly), "L %sD [AR1, P#%u.%u]", type, (value >> 3), (value & 7)); 630 | return 4; 631 | case 0x05: 632 | snprintf(instr->assembly, sizeof(instr->assembly), "T %sB [AR1, P#%u.%u]", type, (value >> 3), (value & 7)); 633 | return 4; 634 | case 0x06: 635 | snprintf(instr->assembly, sizeof(instr->assembly), "T %sW [AR1, P#%u.%u]", type, (value >> 3), (value & 7)); 636 | return 4; 637 | case 0x07: 638 | snprintf(instr->assembly, sizeof(instr->assembly), "T %sD [AR1, P#%u.%u]", type, (value >> 3), (value & 7)); 639 | return 4; 640 | case 0x09: 641 | snprintf(instr->assembly, sizeof(instr->assembly), "L %sB [AR2, P#%u.%u]", type, (value >> 3), (value & 7)); 642 | return 4; 643 | case 0x0A: 644 | snprintf(instr->assembly, sizeof(instr->assembly), "L %sW [AR2, P#%u.%u]", type, (value >> 3), (value & 7)); 645 | return 4; 646 | case 0x0B: 647 | snprintf(instr->assembly, sizeof(instr->assembly), "L %sD [AR2, P#%u.%u]", type, (value >> 3), (value & 7)); 648 | return 4; 649 | case 0x0D: 650 | snprintf(instr->assembly, sizeof(instr->assembly), "T %sB [AR2, P#%u.%u]", type, (value >> 3), (value & 7)); 651 | return 4; 652 | case 0x0E: 653 | snprintf(instr->assembly, sizeof(instr->assembly), "T %sW [AR2, P#%u.%u]", type, (value >> 3), (value & 7)); 654 | return 4; 655 | case 0x0F: 656 | snprintf(instr->assembly, sizeof(instr->assembly), "T %sD [AR2, P#%u.%u]", type, (value >> 3), (value & 7)); 657 | return 4; 658 | default: 659 | return -1; 660 | } 661 | } 662 | return -1; 663 | } 664 | 665 | static int s7_decode_BF(const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 666 | if (buffer[0] == 0x00) { 667 | snprintf(instr->assembly, sizeof(instr->assembly), ")"); 668 | return 2; 669 | } else if (size > 2) { 670 | ut16_t value = s7_ut16(buffer + 1); 671 | switch (buffer[0]) { 672 | case 0x30: 673 | snprintf(instr->assembly, sizeof(instr->assembly), "A T [MW %d]", value); 674 | return 4; 675 | case 0x31: 676 | snprintf(instr->assembly, sizeof(instr->assembly), "AN T [MW %d]", value); 677 | return 4; 678 | case 0x32: 679 | snprintf(instr->assembly, sizeof(instr->assembly), "O T [MW %d]", value); 680 | return 4; 681 | case 0x33: 682 | snprintf(instr->assembly, sizeof(instr->assembly), "ON T [MW %d]", value); 683 | return 4; 684 | case 0x34: 685 | snprintf(instr->assembly, sizeof(instr->assembly), "X T [MW %d]", value); 686 | return 4; 687 | case 0x35: 688 | snprintf(instr->assembly, sizeof(instr->assembly), "XN T [MW %d]", value); 689 | return 4; 690 | case 0x36: 691 | snprintf(instr->assembly, sizeof(instr->assembly), "L T [MW %d]", value); 692 | return 4; 693 | case 0x38: 694 | snprintf(instr->assembly, sizeof(instr->assembly), "FR T [MW %d]", value); 695 | return 4; 696 | case 0x39: 697 | snprintf(instr->assembly, sizeof(instr->assembly), "LC T [MW %d]", value); 698 | return 4; 699 | case 0x3A: 700 | snprintf(instr->assembly, sizeof(instr->assembly), "SF T [MW %d]", value); 701 | return 4; 702 | case 0x3B: 703 | snprintf(instr->assembly, sizeof(instr->assembly), "SE T [MW %d]", value); 704 | return 4; 705 | case 0x3C: 706 | snprintf(instr->assembly, sizeof(instr->assembly), "SD T [MW %d]", value); 707 | return 4; 708 | case 0x3D: 709 | snprintf(instr->assembly, sizeof(instr->assembly), "SS T [MW %d]", value); 710 | return 4; 711 | case 0x3E: 712 | snprintf(instr->assembly, sizeof(instr->assembly), "SP T [MW %d]", value); 713 | return 4; 714 | case 0x3F: 715 | snprintf(instr->assembly, sizeof(instr->assembly), "R T [MW %d]", value); 716 | return 4; 717 | case 0x40: 718 | snprintf(instr->assembly, sizeof(instr->assembly), "A T [DBW %d]", value); 719 | return 4; 720 | case 0x41: 721 | snprintf(instr->assembly, sizeof(instr->assembly), "AN T [DBW %d]", value); 722 | return 4; 723 | case 0x42: 724 | snprintf(instr->assembly, sizeof(instr->assembly), "O T [DBW %d]", value); 725 | return 4; 726 | case 0x43: 727 | snprintf(instr->assembly, sizeof(instr->assembly), "ON T [DBW %d]", value); 728 | return 4; 729 | case 0x44: 730 | snprintf(instr->assembly, sizeof(instr->assembly), "X T [DBW %d]", value); 731 | return 4; 732 | case 0x45: 733 | snprintf(instr->assembly, sizeof(instr->assembly), "XN T [DBW %d]", value); 734 | return 4; 735 | case 0x46: 736 | snprintf(instr->assembly, sizeof(instr->assembly), "L T [DBW %d]", value); 737 | return 4; 738 | case 0x48: 739 | snprintf(instr->assembly, sizeof(instr->assembly), "FR T [DBW %d]", value); 740 | return 4; 741 | case 0x49: 742 | snprintf(instr->assembly, sizeof(instr->assembly), "LC T [DBW %d]", value); 743 | return 4; 744 | case 0x4A: 745 | snprintf(instr->assembly, sizeof(instr->assembly), "SF T [DBW %d]", value); 746 | return 4; 747 | case 0x4B: 748 | snprintf(instr->assembly, sizeof(instr->assembly), "SE T [DBW %d]", value); 749 | return 4; 750 | case 0x4C: 751 | snprintf(instr->assembly, sizeof(instr->assembly), "SD T [DBW %d]", value); 752 | return 4; 753 | case 0x4D: 754 | snprintf(instr->assembly, sizeof(instr->assembly), "SS T [DBW %d]", value); 755 | return 4; 756 | case 0x4E: 757 | snprintf(instr->assembly, sizeof(instr->assembly), "SP T [DBW %d]", value); 758 | return 4; 759 | case 0x4F: 760 | snprintf(instr->assembly, sizeof(instr->assembly), "R T [DBW %d]", value); 761 | return 4; 762 | case 0x50: 763 | snprintf(instr->assembly, sizeof(instr->assembly), "A T [DIW %d]", value); 764 | return 4; 765 | case 0x51: 766 | snprintf(instr->assembly, sizeof(instr->assembly), "AN T [DIW %d]", value); 767 | return 4; 768 | case 0x52: 769 | snprintf(instr->assembly, sizeof(instr->assembly), "O T [DIW %d]", value); 770 | return 4; 771 | case 0x53: 772 | snprintf(instr->assembly, sizeof(instr->assembly), "ON T [DIW %d]", value); 773 | return 4; 774 | case 0x54: 775 | snprintf(instr->assembly, sizeof(instr->assembly), "X T [DIW %d]", value); 776 | return 4; 777 | case 0x55: 778 | snprintf(instr->assembly, sizeof(instr->assembly), "XN T [DIW %d]", value); 779 | return 4; 780 | case 0x58: 781 | snprintf(instr->assembly, sizeof(instr->assembly), "FR T [DIW %d]", value); 782 | return 4; 783 | case 0x5C: 784 | snprintf(instr->assembly, sizeof(instr->assembly), "SD T [DIW %d]", value); 785 | return 4; 786 | case 0x5D: 787 | snprintf(instr->assembly, sizeof(instr->assembly), "SS T [DIW %d]", value); 788 | return 4; 789 | case 0x5E: 790 | snprintf(instr->assembly, sizeof(instr->assembly), "SP T [DIW %d]", value); 791 | return 4; 792 | case 0x5F: 793 | snprintf(instr->assembly, sizeof(instr->assembly), "R T [DIW %d]", value); 794 | return 4; 795 | case 0x60: 796 | snprintf(instr->assembly, sizeof(instr->assembly), "A T [LW %d]", value); 797 | return 4; 798 | case 0x61: 799 | snprintf(instr->assembly, sizeof(instr->assembly), "AN T [LW %d]", value); 800 | return 4; 801 | case 0x62: 802 | snprintf(instr->assembly, sizeof(instr->assembly), "O T [LW %d]", value); 803 | return 4; 804 | case 0x63: 805 | snprintf(instr->assembly, sizeof(instr->assembly), "ON T [LW %d]", value); 806 | return 4; 807 | case 0x64: 808 | snprintf(instr->assembly, sizeof(instr->assembly), "X T [LW %d]", value); 809 | return 4; 810 | case 0x65: 811 | snprintf(instr->assembly, sizeof(instr->assembly), "XN T [LW %d]", value); 812 | return 4; 813 | case 0x66: 814 | snprintf(instr->assembly, sizeof(instr->assembly), "L T [LW %d]", value); 815 | return 4; 816 | case 0x68: 817 | snprintf(instr->assembly, sizeof(instr->assembly), "FR T [LW %d]", value); 818 | return 4; 819 | case 0x69: 820 | snprintf(instr->assembly, sizeof(instr->assembly), "LC T [LW %d]", value); 821 | return 4; 822 | case 0x6A: 823 | snprintf(instr->assembly, sizeof(instr->assembly), "SF T [LW %d]", value); 824 | return 4; 825 | case 0x6B: 826 | snprintf(instr->assembly, sizeof(instr->assembly), "SE T [LW %d]", value); 827 | return 4; 828 | case 0x6C: 829 | snprintf(instr->assembly, sizeof(instr->assembly), "SD T [LW %d]", value); 830 | return 4; 831 | case 0x6D: 832 | snprintf(instr->assembly, sizeof(instr->assembly), "SS T [LW %d]", value); 833 | return 4; 834 | case 0x6E: 835 | snprintf(instr->assembly, sizeof(instr->assembly), "SP T [LW %d]", value); 836 | return 4; 837 | case 0x6F: 838 | snprintf(instr->assembly, sizeof(instr->assembly), "R T [LW %d]", value); 839 | return 4; 840 | case 0xB0: 841 | snprintf(instr->assembly, sizeof(instr->assembly), "A C [MW %d]", value); 842 | return 4; 843 | case 0xB1: 844 | snprintf(instr->assembly, sizeof(instr->assembly), "AN C [MW %d]", value); 845 | return 4; 846 | case 0xB2: 847 | snprintf(instr->assembly, sizeof(instr->assembly), "O C [MW %d]", value); 848 | return 4; 849 | case 0xB3: 850 | snprintf(instr->assembly, sizeof(instr->assembly), "ON C [MW %d]", value); 851 | return 4; 852 | case 0xB4: 853 | snprintf(instr->assembly, sizeof(instr->assembly), "X C [MW %d]", value); 854 | return 4; 855 | case 0xB5: 856 | snprintf(instr->assembly, sizeof(instr->assembly), "XN C [MW %d]", value); 857 | return 4; 858 | case 0xB6: 859 | snprintf(instr->assembly, sizeof(instr->assembly), "L C [MW %d]", value); 860 | return 4; 861 | case 0xB8: 862 | snprintf(instr->assembly, sizeof(instr->assembly), "FR C [MW %d]", value); 863 | return 4; 864 | case 0xB9: 865 | snprintf(instr->assembly, sizeof(instr->assembly), "LC C [MW %d]", value); 866 | return 4; 867 | case 0xBA: 868 | snprintf(instr->assembly, sizeof(instr->assembly), "CD C [MW %d]", value); 869 | return 4; 870 | case 0xBB: 871 | snprintf(instr->assembly, sizeof(instr->assembly), "S C [MW %d]", value); 872 | return 4; 873 | case 0xBD: 874 | snprintf(instr->assembly, sizeof(instr->assembly), "CU C [MW %d]", value); 875 | return 4; 876 | case 0xBF: 877 | snprintf(instr->assembly, sizeof(instr->assembly), "R C [MW %d]", value); 878 | return 4; 879 | case 0xC0: 880 | snprintf(instr->assembly, sizeof(instr->assembly), "A C [DBW %d]", value); 881 | return 4; 882 | case 0xC1: 883 | snprintf(instr->assembly, sizeof(instr->assembly), "AN C [DBW %d]", value); 884 | return 4; 885 | case 0xC2: 886 | snprintf(instr->assembly, sizeof(instr->assembly), "O C [DBW %d]", value); 887 | return 4; 888 | case 0xC3: 889 | snprintf(instr->assembly, sizeof(instr->assembly), "ON C [DBW %d]", value); 890 | return 4; 891 | case 0xC4: 892 | snprintf(instr->assembly, sizeof(instr->assembly), "X C [DBW %d]", value); 893 | return 4; 894 | case 0xC5: 895 | snprintf(instr->assembly, sizeof(instr->assembly), "XN C [DBW %d]", value); 896 | return 4; 897 | case 0xC6: 898 | snprintf(instr->assembly, sizeof(instr->assembly), "L C [DBW %d]", value); 899 | return 4; 900 | case 0xC8: 901 | snprintf(instr->assembly, sizeof(instr->assembly), "FR C [DBW %d]", value); 902 | return 4; 903 | case 0xC9: 904 | snprintf(instr->assembly, sizeof(instr->assembly), "LC C [DBW %d]", value); 905 | return 4; 906 | case 0xCA: 907 | snprintf(instr->assembly, sizeof(instr->assembly), "CD C [DBW %d]", value); 908 | return 4; 909 | case 0xCB: 910 | snprintf(instr->assembly, sizeof(instr->assembly), "S C [DBW %d]", value); 911 | return 4; 912 | case 0xCD: 913 | snprintf(instr->assembly, sizeof(instr->assembly), "CU C [DBW %d]", value); 914 | return 4; 915 | case 0xCF: 916 | snprintf(instr->assembly, sizeof(instr->assembly), "R C [DBW %d]", value); 917 | return 4; 918 | case 0xD0: 919 | snprintf(instr->assembly, sizeof(instr->assembly), "A C [DIW %d]", value); 920 | return 4; 921 | case 0xD1: 922 | snprintf(instr->assembly, sizeof(instr->assembly), "AN C [DIW %d]", value); 923 | return 4; 924 | case 0xD2: 925 | snprintf(instr->assembly, sizeof(instr->assembly), "O C [DIW %d]", value); 926 | return 4; 927 | case 0xD3: 928 | snprintf(instr->assembly, sizeof(instr->assembly), "ON C [DIW %d]", value); 929 | return 4; 930 | case 0xD4: 931 | snprintf(instr->assembly, sizeof(instr->assembly), "X C [DIW %d]", value); 932 | return 4; 933 | case 0xD5: 934 | snprintf(instr->assembly, sizeof(instr->assembly), "XN C [DIW %d]", value); 935 | return 4; 936 | case 0xD6: 937 | snprintf(instr->assembly, sizeof(instr->assembly), "L C [DIW %d]", value); 938 | return 4; 939 | case 0xD8: 940 | snprintf(instr->assembly, sizeof(instr->assembly), "FR C [DIW %d]", value); 941 | return 4; 942 | case 0xD9: 943 | snprintf(instr->assembly, sizeof(instr->assembly), "LC C [DIW %d]", value); 944 | return 4; 945 | case 0xDA: 946 | snprintf(instr->assembly, sizeof(instr->assembly), "CD C [DIW %d]", value); 947 | return 4; 948 | case 0xDB: 949 | snprintf(instr->assembly, sizeof(instr->assembly), "S C [DIW %d]", value); 950 | return 4; 951 | case 0xDD: 952 | snprintf(instr->assembly, sizeof(instr->assembly), "CU C [DIW %d]", value); 953 | return 4; 954 | case 0xDF: 955 | snprintf(instr->assembly, sizeof(instr->assembly), "R C [DIW %d]", value); 956 | return 4; 957 | case 0xE0: 958 | snprintf(instr->assembly, sizeof(instr->assembly), "A C [LW %d]", value); 959 | return 4; 960 | case 0xE1: 961 | snprintf(instr->assembly, sizeof(instr->assembly), "AN C [LW %d]", value); 962 | return 4; 963 | case 0xE2: 964 | snprintf(instr->assembly, sizeof(instr->assembly), "O C [LW %d]", value); 965 | return 4; 966 | case 0xE3: 967 | snprintf(instr->assembly, sizeof(instr->assembly), "ON C [LW %d]", value); 968 | return 4; 969 | case 0xE4: 970 | snprintf(instr->assembly, sizeof(instr->assembly), "X C [LW %d]", value); 971 | return 4; 972 | case 0xE5: 973 | snprintf(instr->assembly, sizeof(instr->assembly), "XN C [LW %d]", value); 974 | return 4; 975 | case 0xE6: 976 | snprintf(instr->assembly, sizeof(instr->assembly), "L C [LW %d]", value); 977 | return 4; 978 | case 0xE8: 979 | snprintf(instr->assembly, sizeof(instr->assembly), "FR C [LW %d]", value); 980 | return 4; 981 | case 0xE9: 982 | snprintf(instr->assembly, sizeof(instr->assembly), "LC C [LW %d]", value); 983 | return 4; 984 | case 0xEA: 985 | snprintf(instr->assembly, sizeof(instr->assembly), "CD C [LW %d]", value); 986 | return 4; 987 | case 0xEB: 988 | snprintf(instr->assembly, sizeof(instr->assembly), "S C [LW %d]", value); 989 | return 4; 990 | case 0xED: 991 | snprintf(instr->assembly, sizeof(instr->assembly), "CU C [LW %d]", value); 992 | return 4; 993 | case 0xEF: 994 | snprintf(instr->assembly, sizeof(instr->assembly), "R C [LW %d]", value); 995 | return 4; 996 | default: 997 | return -1; 998 | } 999 | } 1000 | return -1; 1001 | } 1002 | 1003 | static int s7_decode_FB(const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 1004 | switch (buffer[0]) { 1005 | case 0x00: 1006 | snprintf(instr->assembly, sizeof(instr->assembly), "O"); 1007 | return 2; 1008 | case 0x3C: 1009 | snprintf(instr->assembly, sizeof(instr->assembly), "L DBLG"); 1010 | return 2; 1011 | case 0x3D: 1012 | snprintf(instr->assembly, sizeof(instr->assembly), "L DILG"); 1013 | return 2; 1014 | case 0x4C: 1015 | snprintf(instr->assembly, sizeof(instr->assembly), "L DBNO"); 1016 | return 2; 1017 | case 0x4D: 1018 | snprintf(instr->assembly, sizeof(instr->assembly), "L DINO"); 1019 | return 2; 1020 | case 0x7C: 1021 | snprintf(instr->assembly, sizeof(instr->assembly), "CDB"); 1022 | return 2; 1023 | default: 1024 | break; 1025 | } 1026 | if (size > 2) { 1027 | ut16_t value = s7_ut16(buffer + 1); 1028 | switch (buffer[0]) { 1029 | case 0x01: 1030 | snprintf(instr->assembly, sizeof(instr->assembly), "L B [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1031 | return 4; 1032 | case 0x02: 1033 | snprintf(instr->assembly, sizeof(instr->assembly), "L W [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1034 | return 4; 1035 | case 0x03: 1036 | snprintf(instr->assembly, sizeof(instr->assembly), "L D [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1037 | return 4; 1038 | case 0x05: 1039 | snprintf(instr->assembly, sizeof(instr->assembly), "T B [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1040 | return 4; 1041 | case 0x06: 1042 | snprintf(instr->assembly, sizeof(instr->assembly), "T W [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1043 | return 4; 1044 | case 0x07: 1045 | snprintf(instr->assembly, sizeof(instr->assembly), "T D [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1046 | return 4; 1047 | case 0x09: 1048 | snprintf(instr->assembly, sizeof(instr->assembly), "L B [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1049 | return 4; 1050 | case 0x0B: 1051 | snprintf(instr->assembly, sizeof(instr->assembly), "L W [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1052 | return 4; 1053 | case 0x0C: 1054 | snprintf(instr->assembly, sizeof(instr->assembly), "L D [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1055 | return 4; 1056 | case 0x0D: 1057 | snprintf(instr->assembly, sizeof(instr->assembly), "T B [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1058 | return 4; 1059 | case 0x0E: 1060 | snprintf(instr->assembly, sizeof(instr->assembly), "T W [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1061 | return 4; 1062 | case 0x0F: 1063 | snprintf(instr->assembly, sizeof(instr->assembly), "T D [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1064 | return 4; 1065 | case 0x10: 1066 | snprintf(instr->assembly, sizeof(instr->assembly), "A [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1067 | return 4; 1068 | case 0x11: 1069 | snprintf(instr->assembly, sizeof(instr->assembly), "AN [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1070 | return 4; 1071 | case 0x12: 1072 | snprintf(instr->assembly, sizeof(instr->assembly), "O [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1073 | return 4; 1074 | case 0x13: 1075 | snprintf(instr->assembly, sizeof(instr->assembly), "ON [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1076 | return 4; 1077 | case 0x14: 1078 | snprintf(instr->assembly, sizeof(instr->assembly), "X [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1079 | return 4; 1080 | case 0x15: 1081 | snprintf(instr->assembly, sizeof(instr->assembly), "XN [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1082 | return 4; 1083 | case 0x18: 1084 | snprintf(instr->assembly, sizeof(instr->assembly), "A [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1085 | return 4; 1086 | case 0x19: 1087 | snprintf(instr->assembly, sizeof(instr->assembly), "AN [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1088 | return 4; 1089 | case 0x1A: 1090 | snprintf(instr->assembly, sizeof(instr->assembly), "O [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1091 | return 4; 1092 | case 0x1B: 1093 | snprintf(instr->assembly, sizeof(instr->assembly), "ON [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1094 | return 4; 1095 | case 0x1C: 1096 | snprintf(instr->assembly, sizeof(instr->assembly), "X [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1097 | return 4; 1098 | case 0x1D: 1099 | snprintf(instr->assembly, sizeof(instr->assembly), "XN [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1100 | return 4; 1101 | case 0x20: 1102 | snprintf(instr->assembly, sizeof(instr->assembly), "S [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1103 | return 4; 1104 | case 0x21: 1105 | snprintf(instr->assembly, sizeof(instr->assembly), "R [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1106 | return 4; 1107 | case 0x22: 1108 | snprintf(instr->assembly, sizeof(instr->assembly), "= [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1109 | return 4; 1110 | case 0x24: 1111 | snprintf(instr->assembly, sizeof(instr->assembly), "FP [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1112 | return 4; 1113 | case 0x25: 1114 | snprintf(instr->assembly, sizeof(instr->assembly), "FN [AR1, P#%u.%u]", (value >> 3), (value & 7)); 1115 | return 4; 1116 | case 0x28: 1117 | snprintf(instr->assembly, sizeof(instr->assembly), "S [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1118 | return 4; 1119 | case 0x29: 1120 | snprintf(instr->assembly, sizeof(instr->assembly), "R [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1121 | return 4; 1122 | case 0x2A: 1123 | snprintf(instr->assembly, sizeof(instr->assembly), "= [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1124 | return 4; 1125 | case 0x2C: 1126 | snprintf(instr->assembly, sizeof(instr->assembly), "FP [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1127 | return 4; 1128 | case 0x2D: 1129 | snprintf(instr->assembly, sizeof(instr->assembly), "FN [AR2, P#%u.%u]", (value >> 3), (value & 7)); 1130 | return 4; 1131 | case 0x30: 1132 | snprintf(instr->assembly, sizeof(instr->assembly), "UC FC [MW %u]", value); 1133 | return 4; 1134 | case 0x31: 1135 | snprintf(instr->assembly, sizeof(instr->assembly), "CC FC [MW %u]", value); 1136 | return 4; 1137 | case 0x32: 1138 | snprintf(instr->assembly, sizeof(instr->assembly), "UC FB [MW %u]", value); 1139 | return 4; 1140 | case 0x33: 1141 | snprintf(instr->assembly, sizeof(instr->assembly), "CC FB [MW %u]", value); 1142 | return 4; 1143 | case 0x38: 1144 | snprintf(instr->assembly, sizeof(instr->assembly), "OPN DB [MW %u]", value); 1145 | return 4; 1146 | case 0x39: 1147 | snprintf(instr->assembly, sizeof(instr->assembly), "OPN DI [MW %u]", value); 1148 | return 4; 1149 | case 0x40: 1150 | snprintf(instr->assembly, sizeof(instr->assembly), "UC FC [DBW %u]", value); 1151 | return 4; 1152 | case 0x41: 1153 | snprintf(instr->assembly, sizeof(instr->assembly), "CC FC [DBW %u]", value); 1154 | return 4; 1155 | case 0x42: 1156 | snprintf(instr->assembly, sizeof(instr->assembly), "UC FB [DBW %u]", value); 1157 | return 4; 1158 | case 0x43: 1159 | snprintf(instr->assembly, sizeof(instr->assembly), "CC FB [DBW %u]", value); 1160 | return 4; 1161 | case 0x48: 1162 | snprintf(instr->assembly, sizeof(instr->assembly), "OPN DB [DBW %u]", value); 1163 | return 4; 1164 | case 0x49: 1165 | snprintf(instr->assembly, sizeof(instr->assembly), "OPN DI [DBW %u]", value); 1166 | return 4; 1167 | case 0x50: 1168 | snprintf(instr->assembly, sizeof(instr->assembly), "UC FC [DIW %u]", value); 1169 | return 4; 1170 | case 0x51: 1171 | snprintf(instr->assembly, sizeof(instr->assembly), "CC FC [DIW %u]", value); 1172 | return 4; 1173 | case 0x52: 1174 | snprintf(instr->assembly, sizeof(instr->assembly), "UC FB [DIW %u]", value); 1175 | return 4; 1176 | case 0x53: 1177 | snprintf(instr->assembly, sizeof(instr->assembly), "CC FB [DIW %u]", value); 1178 | return 4; 1179 | case 0x58: 1180 | snprintf(instr->assembly, sizeof(instr->assembly), "OPN DB [DIW %u]", value); 1181 | return 4; 1182 | case 0x59: 1183 | snprintf(instr->assembly, sizeof(instr->assembly), "OPN DI [DIW %u]", value); 1184 | return 4; 1185 | case 0x60: 1186 | snprintf(instr->assembly, sizeof(instr->assembly), "UC FC [LW %u]", value); 1187 | return 4; 1188 | case 0x61: 1189 | snprintf(instr->assembly, sizeof(instr->assembly), "CC FC [LW %u]", value); 1190 | return 4; 1191 | case 0x62: 1192 | snprintf(instr->assembly, sizeof(instr->assembly), "UC FB [LW %u]", value); 1193 | return 4; 1194 | case 0x63: 1195 | snprintf(instr->assembly, sizeof(instr->assembly), "CC FB [LW %u]", value); 1196 | return 4; 1197 | case 0x68: 1198 | snprintf(instr->assembly, sizeof(instr->assembly), "OPN DB [LW %u]", value); 1199 | return 4; 1200 | case 0x69: 1201 | snprintf(instr->assembly, sizeof(instr->assembly), "OPN DI [LW %u]", value); 1202 | return 4; 1203 | case 0x70: 1204 | snprintf(instr->assembly, sizeof(instr->assembly), "UC FC %u", value); 1205 | return 4; 1206 | case 0x71: 1207 | snprintf(instr->assembly, sizeof(instr->assembly), "CC FC %u", value); 1208 | return 4; 1209 | case 0x72: 1210 | snprintf(instr->assembly, sizeof(instr->assembly), "UC FC %u", value); 1211 | return 4; 1212 | case 0x73: 1213 | snprintf(instr->assembly, sizeof(instr->assembly), "CC FB %u", value); 1214 | return 4; 1215 | case 0x74: 1216 | snprintf(instr->assembly, sizeof(instr->assembly), "UC SFC %u", value); 1217 | return 4; 1218 | case 0x76: 1219 | snprintf(instr->assembly, sizeof(instr->assembly), "UC SFB %u", value); 1220 | return 4; 1221 | case 0x78: 1222 | snprintf(instr->assembly, sizeof(instr->assembly), "OPN DB %u", value); 1223 | return 4; 1224 | case 0x79: 1225 | snprintf(instr->assembly, sizeof(instr->assembly), "OPN DI %u", value); 1226 | return 4; 1227 | case 0x80: 1228 | snprintf(instr->assembly, sizeof(instr->assembly), "A [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BOOLEAN 1229 | return 4; 1230 | case 0x81: 1231 | snprintf(instr->assembly, sizeof(instr->assembly), "AN [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BOOLEAN 1232 | return 4; 1233 | case 0x82: 1234 | snprintf(instr->assembly, sizeof(instr->assembly), "O [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BOOLEAN 1235 | return 4; 1236 | case 0x83: 1237 | snprintf(instr->assembly, sizeof(instr->assembly), "ON [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BOOLEAN 1238 | return 4; 1239 | case 0x84: 1240 | snprintf(instr->assembly, sizeof(instr->assembly), "X [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BOOLEAN 1241 | return 4; 1242 | case 0x85: 1243 | snprintf(instr->assembly, sizeof(instr->assembly), "XN [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BOOLEAN 1244 | return 4; 1245 | case 0x90: 1246 | snprintf(instr->assembly, sizeof(instr->assembly), "S [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BOOLEAN 1247 | return 4; 1248 | case 0x91: 1249 | snprintf(instr->assembly, sizeof(instr->assembly), "R [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BOOLEAN 1250 | return 4; 1251 | case 0x92: 1252 | snprintf(instr->assembly, sizeof(instr->assembly), "= [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BOOLEAN 1253 | return 4; 1254 | case 0x94: 1255 | snprintf(instr->assembly, sizeof(instr->assembly), "FP [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BOOLEAN 1256 | return 4; 1257 | case 0x95: 1258 | snprintf(instr->assembly, sizeof(instr->assembly), "FN [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BOOLEAN 1259 | return 4; 1260 | case 0xA0: 1261 | snprintf(instr->assembly, sizeof(instr->assembly), "A [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1262 | return 4; 1263 | case 0xA1: 1264 | snprintf(instr->assembly, sizeof(instr->assembly), "AN [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1265 | return 4; 1266 | case 0xA2: 1267 | snprintf(instr->assembly, sizeof(instr->assembly), "O [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1268 | return 4; 1269 | case 0xA3: 1270 | snprintf(instr->assembly, sizeof(instr->assembly), "ON [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1271 | return 4; 1272 | case 0xA4: 1273 | snprintf(instr->assembly, sizeof(instr->assembly), "X [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1274 | return 4; 1275 | case 0xA5: 1276 | snprintf(instr->assembly, sizeof(instr->assembly), "XN [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1277 | return 4; 1278 | case 0xA6: 1279 | snprintf(instr->assembly, sizeof(instr->assembly), "L [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1280 | return 4; 1281 | case 0xA8: 1282 | snprintf(instr->assembly, sizeof(instr->assembly), "FR [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1283 | return 4; 1284 | case 0xA9: 1285 | snprintf(instr->assembly, sizeof(instr->assembly), "LC [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1286 | return 4; 1287 | case 0xAA: 1288 | snprintf(instr->assembly, sizeof(instr->assembly), "SF [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1289 | return 4; 1290 | case 0xAB: 1291 | snprintf(instr->assembly, sizeof(instr->assembly), "SE [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1292 | return 4; 1293 | case 0xAC: 1294 | snprintf(instr->assembly, sizeof(instr->assembly), "SD [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1295 | return 4; 1296 | case 0xAD: 1297 | snprintf(instr->assembly, sizeof(instr->assembly), "SS [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1298 | return 4; 1299 | case 0xAE: 1300 | snprintf(instr->assembly, sizeof(instr->assembly), "SP [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1301 | return 4; 1302 | case 0xAF: 1303 | snprintf(instr->assembly, sizeof(instr->assembly), "R [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_TIMER 1304 | return 4; 1305 | case 0xB0: 1306 | snprintf(instr->assembly, sizeof(instr->assembly), "A [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1307 | return 4; 1308 | case 0xB1: 1309 | snprintf(instr->assembly, sizeof(instr->assembly), "AN [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1310 | return 4; 1311 | case 0xB2: 1312 | snprintf(instr->assembly, sizeof(instr->assembly), "O [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1313 | return 4; 1314 | case 0xB3: 1315 | snprintf(instr->assembly, sizeof(instr->assembly), "ON [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1316 | return 4; 1317 | case 0xB4: 1318 | snprintf(instr->assembly, sizeof(instr->assembly), "X [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1319 | return 4; 1320 | case 0xB5: 1321 | snprintf(instr->assembly, sizeof(instr->assembly), "XN [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1322 | return 4; 1323 | case 0xB6: 1324 | snprintf(instr->assembly, sizeof(instr->assembly), "L [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1325 | return 4; 1326 | case 0xB8: 1327 | snprintf(instr->assembly, sizeof(instr->assembly), "FR [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1328 | return 4; 1329 | case 0xB9: 1330 | snprintf(instr->assembly, sizeof(instr->assembly), "LC [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1331 | return 4; 1332 | case 0xBA: 1333 | snprintf(instr->assembly, sizeof(instr->assembly), "CD [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1334 | return 4; 1335 | case 0xBB: 1336 | snprintf(instr->assembly, sizeof(instr->assembly), "S [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1337 | return 4; 1338 | case 0xBD: 1339 | snprintf(instr->assembly, sizeof(instr->assembly), "CU [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1340 | return 4; 1341 | case 0xBF: 1342 | snprintf(instr->assembly, sizeof(instr->assembly), "R [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_COUNTER 1343 | return 4; 1344 | case 0xC1: 1345 | snprintf(instr->assembly, sizeof(instr->assembly), "L [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BYTE 1346 | return 4; 1347 | case 0xC2: 1348 | snprintf(instr->assembly, sizeof(instr->assembly), "L [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_WORD 1349 | return 4; 1350 | case 0xC3: 1351 | snprintf(instr->assembly, sizeof(instr->assembly), "L [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_DWORD 1352 | return 4; 1353 | case 0xC5: 1354 | snprintf(instr->assembly, sizeof(instr->assembly), "T [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BYTE 1355 | return 4; 1356 | case 0xC6: 1357 | snprintf(instr->assembly, sizeof(instr->assembly), "T [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_WORD 1358 | return 4; 1359 | case 0xC7: 1360 | snprintf(instr->assembly, sizeof(instr->assembly), "T [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_DWORD 1361 | return 4; 1362 | case 0xD0: 1363 | snprintf(instr->assembly, sizeof(instr->assembly), "UC [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BLOCK_FC 1364 | return 4; 1365 | case 0xD2: 1366 | snprintf(instr->assembly, sizeof(instr->assembly), "UC [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BLOCK_FB 1367 | return 4; 1368 | case 0xD8: 1369 | snprintf(instr->assembly, sizeof(instr->assembly), "OPN [P#%u.%u]", (value >> 1), (value & 1)); // PARAMETER_BLOCK_DB 1370 | return 4; 1371 | case 0xE0: 1372 | snprintf(instr->assembly, sizeof(instr->assembly), "A T %u", value); 1373 | return 4; 1374 | case 0xE1: 1375 | snprintf(instr->assembly, sizeof(instr->assembly), "AN T %u", value); 1376 | return 4; 1377 | case 0xE2: 1378 | snprintf(instr->assembly, sizeof(instr->assembly), "O T %u", value); 1379 | return 4; 1380 | case 0xE3: 1381 | snprintf(instr->assembly, sizeof(instr->assembly), "ON T %u", value); 1382 | return 4; 1383 | case 0xE4: 1384 | snprintf(instr->assembly, sizeof(instr->assembly), "X T %u", value); 1385 | return 4; 1386 | case 0xE5: 1387 | snprintf(instr->assembly, sizeof(instr->assembly), "XN T %u", value); 1388 | return 4; 1389 | case 0xE6: 1390 | snprintf(instr->assembly, sizeof(instr->assembly), "L T %u", value); 1391 | return 4; 1392 | case 0xE8: 1393 | snprintf(instr->assembly, sizeof(instr->assembly), "FR T %u", value); 1394 | return 4; 1395 | case 0xE9: 1396 | snprintf(instr->assembly, sizeof(instr->assembly), "LC T %u", value); 1397 | return 4; 1398 | case 0xEA: 1399 | snprintf(instr->assembly, sizeof(instr->assembly), "SF T %u", value); 1400 | return 4; 1401 | case 0xEB: 1402 | snprintf(instr->assembly, sizeof(instr->assembly), "SE T %u", value); 1403 | return 4; 1404 | case 0xEC: 1405 | snprintf(instr->assembly, sizeof(instr->assembly), "SD T %u", value); 1406 | return 4; 1407 | case 0xED: 1408 | snprintf(instr->assembly, sizeof(instr->assembly), "SS T %u", value); 1409 | return 4; 1410 | case 0xEE: 1411 | snprintf(instr->assembly, sizeof(instr->assembly), "SP T %u", value); 1412 | return 4; 1413 | case 0xEF: 1414 | snprintf(instr->assembly, sizeof(instr->assembly), "R T %u", value); 1415 | return 4; 1416 | case 0xF0: 1417 | snprintf(instr->assembly, sizeof(instr->assembly), "A C %u", value); 1418 | return 4; 1419 | case 0xF1: 1420 | snprintf(instr->assembly, sizeof(instr->assembly), "AN C %u", value); 1421 | return 4; 1422 | case 0xF2: 1423 | snprintf(instr->assembly, sizeof(instr->assembly), "O C %u", value); 1424 | return 4; 1425 | case 0xF3: 1426 | snprintf(instr->assembly, sizeof(instr->assembly), "ON C %u", value); 1427 | return 4; 1428 | case 0xF4: 1429 | snprintf(instr->assembly, sizeof(instr->assembly), "X C %u", value); 1430 | return 4; 1431 | case 0xF5: 1432 | snprintf(instr->assembly, sizeof(instr->assembly), "XN C %u", value); 1433 | return 4; 1434 | case 0xF6: 1435 | snprintf(instr->assembly, sizeof(instr->assembly), "L C %u", value); 1436 | return 4; 1437 | case 0xF8: 1438 | snprintf(instr->assembly, sizeof(instr->assembly), "FR C %u", value); 1439 | return 4; 1440 | case 0xF9: 1441 | snprintf(instr->assembly, sizeof(instr->assembly), "LC C %u", value); 1442 | return 4; 1443 | case 0xFA: 1444 | snprintf(instr->assembly, sizeof(instr->assembly), "CD %u", value); 1445 | return 4; 1446 | case 0xFB: 1447 | snprintf(instr->assembly, sizeof(instr->assembly), "S %u", value); 1448 | return 4; 1449 | case 0xFD: 1450 | snprintf(instr->assembly, sizeof(instr->assembly), "CU %u", value); 1451 | return 4; 1452 | case 0xFF: 1453 | snprintf(instr->assembly, sizeof(instr->assembly), "R %u", value); 1454 | return 4; 1455 | default: 1456 | return -1; 1457 | } 1458 | } 1459 | return -1; 1460 | } 1461 | 1462 | static int s7_decode_FE(const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 1463 | if ((buffer[0] & 0xF0) == 0xC0) { 1464 | ut8_t value = (buffer[0] & 0x0F); 1465 | snprintf(instr->assembly, sizeof(instr->assembly), "SRD %u", value); 1466 | return 2; 1467 | } 1468 | switch (buffer[0]) { 1469 | case 0x01: 1470 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR1 AR2"); 1471 | return 2; 1472 | case 0x04: 1473 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR1"); 1474 | return 2; 1475 | case 0x05: 1476 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR1"); 1477 | return 2; 1478 | case 0x06: 1479 | snprintf(instr->assembly, sizeof(instr->assembly), "+AR1"); 1480 | return 2; 1481 | case 0x08: 1482 | snprintf(instr->assembly, sizeof(instr->assembly), "CAR"); 1483 | return 2; 1484 | case 0x09: 1485 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR1 AR2"); 1486 | return 2; 1487 | case 0x0C: 1488 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR2"); 1489 | return 2; 1490 | case 0x0D: 1491 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR2"); 1492 | return 2; 1493 | case 0x0E: 1494 | snprintf(instr->assembly, sizeof(instr->assembly), "+AR2"); 1495 | return 2; 1496 | default: 1497 | break; 1498 | } 1499 | if (size > 2) { 1500 | switch (buffer[0]) { 1501 | case 0x03: 1502 | if (size > 4) { 1503 | ut32_t value = s7_ut32(buffer + 1); 1504 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR1 P#%u.%u", (value >> 1), (value & 1)); 1505 | return 6; 1506 | } 1507 | return -1; 1508 | case 0x0B: 1509 | if (size > 4) { 1510 | ut32_t value = s7_ut32(buffer + 1); 1511 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR2 P#%u.%u", (value >> 1), (value & 1)); 1512 | return 6; 1513 | } 1514 | return -1; 1515 | case 0x02: { 1516 | ut16_t value = s7_ut16(buffer + 1); 1517 | snprintf(instr->assembly, sizeof(instr->assembly), "+AR1 P#%u.%u", (value & 0xFFF), (value >> 12)); 1518 | return 4; 1519 | } 1520 | case 0x0A: { 1521 | ut16_t value = s7_ut16(buffer + 1); 1522 | snprintf(instr->assembly, sizeof(instr->assembly), "+AR2 P#%u.%u", (value & 0xFFF), (value >> 12)); 1523 | return 4; 1524 | } 1525 | case 0x33: { 1526 | ut16_t value = s7_ut16(buffer + 1); 1527 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR1 MD %u", value); 1528 | return 4; 1529 | } 1530 | case 0x37: { 1531 | ut16_t value = s7_ut16(buffer + 1); 1532 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR1 MD %u", value); 1533 | return 4; 1534 | } 1535 | case 0x3B: { 1536 | ut16_t value = s7_ut16(buffer + 1); 1537 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR2 MD %u", value); 1538 | return 4; 1539 | } 1540 | case 0x3F: { 1541 | ut16_t value = s7_ut16(buffer + 1); 1542 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR2 MD %u", value); 1543 | return 4; 1544 | } 1545 | case 0x43: { 1546 | ut16_t value = s7_ut16(buffer + 1); 1547 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR1 DBD %u", value); 1548 | return 4; 1549 | } 1550 | case 0x47: { 1551 | ut16_t value = s7_ut16(buffer + 1); 1552 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR1 DBD %u", value); 1553 | return 4; 1554 | } 1555 | case 0x4B: { 1556 | ut16_t value = s7_ut16(buffer + 1); 1557 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR2 DBD %u", value); 1558 | return 4; 1559 | } 1560 | case 0x4F: { 1561 | ut16_t value = s7_ut16(buffer + 1); 1562 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR2 DBD %u", value); 1563 | return 4; 1564 | } 1565 | case 0x53: { 1566 | ut16_t value = s7_ut16(buffer + 1); 1567 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR1 DID %u", value); 1568 | return 4; 1569 | } 1570 | case 0x57: { 1571 | ut16_t value = s7_ut16(buffer + 1); 1572 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR1 DID %u", value); 1573 | return 4; 1574 | } 1575 | case 0x5B: { 1576 | ut16_t value = s7_ut16(buffer + 1); 1577 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR2 DID %u", value); 1578 | return 4; 1579 | } 1580 | case 0x5F: { 1581 | ut16_t value = s7_ut16(buffer + 1); 1582 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR2 DID %u", value); 1583 | return 4; 1584 | } 1585 | case 0x63: { 1586 | ut16_t value = s7_ut16(buffer + 1); 1587 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR1 LD %u", value); 1588 | return 4; 1589 | } 1590 | case 0x67: { 1591 | ut16_t value = s7_ut16(buffer + 1); 1592 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR1 LD %u", value); 1593 | return 4; 1594 | } 1595 | case 0x6B: { 1596 | ut16_t value = s7_ut16(buffer + 1); 1597 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR2 LD %u", value); 1598 | return 4; 1599 | } 1600 | case 0x6F: { 1601 | ut16_t value = s7_ut16(buffer + 1); 1602 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR2 LD %u", value); 1603 | return 4; 1604 | } 1605 | } 1606 | } 1607 | return -1; 1608 | } 1609 | 1610 | static int s7_decode_FF(ut64_t addr, const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 1611 | switch (buffer[0]) { 1612 | case 0x00: 1613 | snprintf(instr->assembly, sizeof(instr->assembly), "A OS"); 1614 | return 2; 1615 | case 0x01: 1616 | snprintf(instr->assembly, sizeof(instr->assembly), "AN OS"); 1617 | return 2; 1618 | case 0x02: 1619 | snprintf(instr->assembly, sizeof(instr->assembly), "O OS"); 1620 | return 2; 1621 | case 0x03: 1622 | snprintf(instr->assembly, sizeof(instr->assembly), "ON OS"); 1623 | return 2; 1624 | case 0x04: 1625 | snprintf(instr->assembly, sizeof(instr->assembly), "X OS"); 1626 | return 2; 1627 | case 0x05: 1628 | snprintf(instr->assembly, sizeof(instr->assembly), "XN OS"); 1629 | return 2; 1630 | case 0x10: 1631 | snprintf(instr->assembly, sizeof(instr->assembly), "A OV"); 1632 | return 2; 1633 | case 0x11: 1634 | snprintf(instr->assembly, sizeof(instr->assembly), "AN OV"); 1635 | return 2; 1636 | case 0x12: 1637 | snprintf(instr->assembly, sizeof(instr->assembly), "O OV"); 1638 | return 2; 1639 | case 0x13: 1640 | snprintf(instr->assembly, sizeof(instr->assembly), "ON OV"); 1641 | return 2; 1642 | case 0x14: 1643 | snprintf(instr->assembly, sizeof(instr->assembly), "X OV"); 1644 | return 2; 1645 | case 0x15: 1646 | snprintf(instr->assembly, sizeof(instr->assembly), "XN OV"); 1647 | return 2; 1648 | case 0x20: 1649 | snprintf(instr->assembly, sizeof(instr->assembly), "A >0"); 1650 | return 2; 1651 | case 0x21: 1652 | snprintf(instr->assembly, sizeof(instr->assembly), "AN >0"); 1653 | return 2; 1654 | case 0x22: 1655 | snprintf(instr->assembly, sizeof(instr->assembly), "O >0"); 1656 | return 2; 1657 | case 0x23: 1658 | snprintf(instr->assembly, sizeof(instr->assembly), "ON >0"); 1659 | return 2; 1660 | case 0x24: 1661 | snprintf(instr->assembly, sizeof(instr->assembly), "X >0"); 1662 | return 2; 1663 | case 0x25: 1664 | snprintf(instr->assembly, sizeof(instr->assembly), "XN >0"); 1665 | return 2; 1666 | case 0x40: 1667 | snprintf(instr->assembly, sizeof(instr->assembly), "A <0"); 1668 | return 2; 1669 | case 0x41: 1670 | snprintf(instr->assembly, sizeof(instr->assembly), "AN <0"); 1671 | return 2; 1672 | case 0x42: 1673 | snprintf(instr->assembly, sizeof(instr->assembly), "O <0"); 1674 | return 2; 1675 | case 0x43: 1676 | snprintf(instr->assembly, sizeof(instr->assembly), "ON <0"); 1677 | return 2; 1678 | case 0x44: 1679 | snprintf(instr->assembly, sizeof(instr->assembly), "X <0"); 1680 | return 2; 1681 | case 0x45: 1682 | snprintf(instr->assembly, sizeof(instr->assembly), "XN <0"); 1683 | return 2; 1684 | case 0x50: 1685 | snprintf(instr->assembly, sizeof(instr->assembly), "A UO"); 1686 | return 2; 1687 | case 0x51: 1688 | snprintf(instr->assembly, sizeof(instr->assembly), "AN UO"); 1689 | return 2; 1690 | case 0x52: 1691 | snprintf(instr->assembly, sizeof(instr->assembly), "O UO"); 1692 | return 2; 1693 | case 0x53: 1694 | snprintf(instr->assembly, sizeof(instr->assembly), "ON UO"); 1695 | return 2; 1696 | case 0x54: 1697 | snprintf(instr->assembly, sizeof(instr->assembly), "X UO"); 1698 | return 2; 1699 | case 0x55: 1700 | snprintf(instr->assembly, sizeof(instr->assembly), "XN UO"); 1701 | return 2; 1702 | case 0x60: 1703 | snprintf(instr->assembly, sizeof(instr->assembly), "A <>0"); 1704 | return 2; 1705 | case 0x61: 1706 | snprintf(instr->assembly, sizeof(instr->assembly), "AN <>0"); 1707 | return 2; 1708 | case 0x62: 1709 | snprintf(instr->assembly, sizeof(instr->assembly), "O <>0"); 1710 | return 2; 1711 | case 0x63: 1712 | snprintf(instr->assembly, sizeof(instr->assembly), "ON <>0"); 1713 | return 2; 1714 | case 0x64: 1715 | snprintf(instr->assembly, sizeof(instr->assembly), "X <>0"); 1716 | return 2; 1717 | case 0x65: 1718 | snprintf(instr->assembly, sizeof(instr->assembly), "XN <>0"); 1719 | return 2; 1720 | case 0x80: 1721 | snprintf(instr->assembly, sizeof(instr->assembly), "A ==0"); 1722 | return 2; 1723 | case 0x81: 1724 | snprintf(instr->assembly, sizeof(instr->assembly), "AN ==0"); 1725 | return 2; 1726 | case 0x82: 1727 | snprintf(instr->assembly, sizeof(instr->assembly), "O ==0"); 1728 | return 2; 1729 | case 0x83: 1730 | snprintf(instr->assembly, sizeof(instr->assembly), "ON ==0"); 1731 | return 2; 1732 | case 0x84: 1733 | snprintf(instr->assembly, sizeof(instr->assembly), "X ==0"); 1734 | return 2; 1735 | case 0x85: 1736 | snprintf(instr->assembly, sizeof(instr->assembly), "XN ==0"); 1737 | return 2; 1738 | case 0xA0: 1739 | snprintf(instr->assembly, sizeof(instr->assembly), "A >=0"); 1740 | return 2; 1741 | case 0xA1: 1742 | snprintf(instr->assembly, sizeof(instr->assembly), "AN >=0"); 1743 | return 2; 1744 | case 0xA2: 1745 | snprintf(instr->assembly, sizeof(instr->assembly), "O >=0"); 1746 | return 2; 1747 | case 0xA3: 1748 | snprintf(instr->assembly, sizeof(instr->assembly), "ON >=0"); 1749 | return 2; 1750 | case 0xA4: 1751 | snprintf(instr->assembly, sizeof(instr->assembly), "X >=0"); 1752 | return 2; 1753 | case 0xA5: 1754 | snprintf(instr->assembly, sizeof(instr->assembly), "XN >=0"); 1755 | return 2; 1756 | case 0xC0: 1757 | snprintf(instr->assembly, sizeof(instr->assembly), "A <=0"); 1758 | return 2; 1759 | case 0xC1: 1760 | snprintf(instr->assembly, sizeof(instr->assembly), "AN <=0"); 1761 | return 2; 1762 | case 0xC2: 1763 | snprintf(instr->assembly, sizeof(instr->assembly), "O <=0"); 1764 | return 2; 1765 | case 0xC3: 1766 | snprintf(instr->assembly, sizeof(instr->assembly), "ON <=0"); 1767 | return 2; 1768 | case 0xC4: 1769 | snprintf(instr->assembly, sizeof(instr->assembly), "X <=0"); 1770 | return 2; 1771 | case 0xC5: 1772 | snprintf(instr->assembly, sizeof(instr->assembly), "XN <=0"); 1773 | return 2; 1774 | case 0xE0: 1775 | snprintf(instr->assembly, sizeof(instr->assembly), "A BR"); 1776 | return 2; 1777 | case 0xE1: 1778 | snprintf(instr->assembly, sizeof(instr->assembly), "AN BR"); 1779 | return 2; 1780 | case 0xE2: 1781 | snprintf(instr->assembly, sizeof(instr->assembly), "O BR"); 1782 | return 2; 1783 | case 0xE3: 1784 | snprintf(instr->assembly, sizeof(instr->assembly), "ON BR"); 1785 | return 2; 1786 | case 0xE4: 1787 | snprintf(instr->assembly, sizeof(instr->assembly), "X BR"); 1788 | return 2; 1789 | case 0xE5: 1790 | snprintf(instr->assembly, sizeof(instr->assembly), "XN BR"); 1791 | return 2; 1792 | case 0xF1: 1793 | snprintf(instr->assembly, sizeof(instr->assembly), "AN("); 1794 | return 2; 1795 | case 0xF3: 1796 | snprintf(instr->assembly, sizeof(instr->assembly), "ON("); 1797 | return 2; 1798 | case 0xF4: 1799 | snprintf(instr->assembly, sizeof(instr->assembly), "X("); 1800 | return 2; 1801 | case 0xF5: 1802 | snprintf(instr->assembly, sizeof(instr->assembly), "XN("); 1803 | return 2; 1804 | case 0xFF: 1805 | snprintf(instr->assembly, sizeof(instr->assembly), "NOP 1"); 1806 | return 2; 1807 | default: 1808 | break; 1809 | } 1810 | if (size > 2) { 1811 | st16_t value = (st16_t)s7_ut16(buffer + 1); 1812 | addr += value; 1813 | instr->jump = addr; 1814 | switch (buffer[0]) { 1815 | case 0x08: 1816 | snprintf(instr->assembly, sizeof(instr->assembly), "JOS 0x%" PFMT64x, addr); 1817 | return 4; 1818 | case 0x18: 1819 | snprintf(instr->assembly, sizeof(instr->assembly), "JO 0x%" PFMT64x, addr); 1820 | return 4; 1821 | case 0x28: 1822 | snprintf(instr->assembly, sizeof(instr->assembly), "JP 0x%" PFMT64x, addr); 1823 | return 4; 1824 | case 0x48: 1825 | snprintf(instr->assembly, sizeof(instr->assembly), "JM 0x%" PFMT64x, addr); 1826 | return 4; 1827 | case 0x58: 1828 | snprintf(instr->assembly, sizeof(instr->assembly), "JUO 0x%" PFMT64x, addr); 1829 | return 4; 1830 | case 0x68: 1831 | snprintf(instr->assembly, sizeof(instr->assembly), "JN 0x%" PFMT64x, addr); 1832 | return 4; 1833 | case 0x78: 1834 | snprintf(instr->assembly, sizeof(instr->assembly), "JNBI 0x%" PFMT64x, addr); 1835 | return 4; 1836 | case 0x88: 1837 | snprintf(instr->assembly, sizeof(instr->assembly), "JZ 0x%" PFMT64x, addr); 1838 | return 4; 1839 | case 0x98: 1840 | snprintf(instr->assembly, sizeof(instr->assembly), "JNB 0x%" PFMT64x, addr); 1841 | return 4; 1842 | case 0xA8: 1843 | snprintf(instr->assembly, sizeof(instr->assembly), "JPZ 0x%" PFMT64x, addr); 1844 | return 4; 1845 | case 0xB8: 1846 | snprintf(instr->assembly, sizeof(instr->assembly), "JCN 0x%" PFMT64x, addr); 1847 | return 4; 1848 | case 0xC8: 1849 | snprintf(instr->assembly, sizeof(instr->assembly), "JMZ 0x%" PFMT64x, addr); 1850 | return 4; 1851 | case 0xD8: 1852 | snprintf(instr->assembly, sizeof(instr->assembly), "JCB 0x%" PFMT64x, addr); 1853 | return 4; 1854 | case 0xE8: 1855 | snprintf(instr->assembly, sizeof(instr->assembly), "JBI 0x%" PFMT64x, addr); 1856 | return 4; 1857 | case 0xF8: 1858 | snprintf(instr->assembly, sizeof(instr->assembly), "JC 0x%" PFMT64x, addr); 1859 | return 4; 1860 | default: 1861 | instr->jump = S7_INVALID_JUMP; 1862 | return -1; 1863 | } 1864 | } 1865 | return -1; 1866 | } 1867 | 1868 | static int s7_decode_200A(const ut8_t *buffer, const ut64_t size, S7Instr *instr) { 1869 | if (size < 5) { 1870 | return -1; 1871 | } 1872 | ut8_t db = buffer[0]; 1873 | switch (buffer[1]) { 1874 | case 0x05: 1875 | switch ((buffer[2] & 0xF0)) { 1876 | case 0xC0: { 1877 | ut8_t n = buffer[2] & 0x0F; 1878 | ut16_t value = s7_ut16(buffer + 3); 1879 | snprintf(instr->assembly, sizeof(instr->assembly), "XN DB%u.DBX %u.%u", db, value, n); 1880 | return 6; 1881 | } 1882 | default: 1883 | return -1; 1884 | } 1885 | case 0xFE: 1886 | switch (buffer[2]) { 1887 | case 0x33: { 1888 | ut16_t value = s7_ut16(buffer + 3); 1889 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR1 DB%u.MD %u", db, value); 1890 | return 6; 1891 | } 1892 | case 0x37: { 1893 | ut16_t value = s7_ut16(buffer + 3); 1894 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR1 DB%u.MD %u", db, value); 1895 | return 6; 1896 | } 1897 | case 0x3B: { 1898 | ut16_t value = s7_ut16(buffer + 3); 1899 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR2 DB%u.MD %u", db, value); 1900 | return 6; 1901 | } 1902 | case 0x3F: { 1903 | ut16_t value = s7_ut16(buffer + 3); 1904 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR2 DB%u.MD %u", db, value); 1905 | return 6; 1906 | } 1907 | case 0x43: { 1908 | ut16_t value = s7_ut16(buffer + 3); 1909 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR1 DB%u.DBD %u", db, value); 1910 | return 6; 1911 | } 1912 | case 0x47: { 1913 | ut16_t value = s7_ut16(buffer + 3); 1914 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR1 DB%u.DBD %u", db, value); 1915 | return 6; 1916 | } 1917 | case 0x4B: { 1918 | ut16_t value = s7_ut16(buffer + 3); 1919 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR2 DB%u.DBD %u", db, value); 1920 | return 6; 1921 | } 1922 | case 0x4F: { 1923 | ut16_t value = s7_ut16(buffer + 3); 1924 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR2 DB%u.DBD %u", db, value); 1925 | return 6; 1926 | } 1927 | case 0x53: { 1928 | ut16_t value = s7_ut16(buffer + 3); 1929 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR1 DB%u.DID %u", db, value); 1930 | return 6; 1931 | } 1932 | case 0x57: { 1933 | ut16_t value = s7_ut16(buffer + 3); 1934 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR1 DB%u.DID %u", db, value); 1935 | return 6; 1936 | } 1937 | case 0x5B: { 1938 | ut16_t value = s7_ut16(buffer + 3); 1939 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR2 DB%u.DID %u", db, value); 1940 | return 6; 1941 | } 1942 | case 0x5F: { 1943 | ut16_t value = s7_ut16(buffer + 3); 1944 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR2 DB%u.DID %u", db, value); 1945 | return 6; 1946 | } 1947 | case 0x63: { 1948 | ut16_t value = s7_ut16(buffer + 3); 1949 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR1 DB%u.LD %u", db, value); 1950 | return 6; 1951 | } 1952 | case 0x67: { 1953 | ut16_t value = s7_ut16(buffer + 3); 1954 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR1 DB%u.LD %u", db, value); 1955 | return 6; 1956 | } 1957 | case 0x6B: { 1958 | ut16_t value = s7_ut16(buffer + 3); 1959 | snprintf(instr->assembly, sizeof(instr->assembly), "LAR2 DB%u.LD %u", db, value); 1960 | return 6; 1961 | } 1962 | case 0x6F: { 1963 | ut16_t value = s7_ut16(buffer + 3); 1964 | snprintf(instr->assembly, sizeof(instr->assembly), "TAR2 DB%u.LD %u", db, value); 1965 | return 6; 1966 | } 1967 | default: 1968 | return -1; 1969 | } 1970 | default: 1971 | return -1; 1972 | } 1973 | } 1974 | 1975 | int simatic_s7_decode_instruction(const ut8_t *buffer, const ut64_t size, const ut64_t addr, S7Instr *instr) { 1976 | if (!buffer || size < 2 || !instr) { 1977 | return -1; 1978 | } 1979 | snprintf(instr->assembly, sizeof(instr->assembly), "invalid"); 1980 | instr->jump = S7_INVALID_JUMP; 1981 | instr->is_return = false; 1982 | 1983 | switch (buffer[0]) { 1984 | case 0x00: 1985 | return s7_decode_bitlogic("NOP 0", "A", "AN", buffer + 1, size - 1, instr); 1986 | case 0x01: 1987 | return s7_decode_bitlogic("INVI", "O", "ON", buffer + 1, size - 1, instr); 1988 | case 0x02: 1989 | return s7_decode_byte("L", "T ", buffer + 1, size - 1, instr); 1990 | case 0x04: 1991 | return s7_decode_byte("FR", "T ", buffer + 1, size - 1, instr); 1992 | case 0x05: 1993 | return s7_decode_bitlogic("BEC", "X", "XN", buffer + 1, size - 1, instr); 1994 | case 0x09: 1995 | return s7_decode_bitlogic("NEGI", "S", "R", buffer + 1, size - 1, instr); 1996 | case 0x0A: 1997 | return s7_decode_byte("L", "MB ", buffer + 1, size - 1, instr); 1998 | case 0x0B: 1999 | return s7_decode_byte("T", "MB ", buffer + 1, size - 1, instr); 2000 | case 0x0C: 2001 | return s7_decode_byte("LC", "T ", buffer + 1, size - 1, instr); 2002 | case 0x10: { 2003 | int ret = s7_decode_byte("BLD", "", buffer + 1, size - 1, instr); 2004 | if (ret > 0) { 2005 | instr->is_return = true; 2006 | } 2007 | return ret; 2008 | } 2009 | case 0x11: 2010 | return s7_decode_byte("INC", "", buffer + 1, size - 1, instr); 2011 | case 0x12: 2012 | return s7_decode_byte("L", "MW ", buffer + 1, size - 1, instr); 2013 | case 0x13: 2014 | return s7_decode_byte("T", "MW ", buffer + 1, size - 1, instr); 2015 | case 0x14: 2016 | return s7_decode_byte("SF", "T ", buffer + 1, size - 1, instr); 2017 | case 0x19: 2018 | return s7_decode_byte("DEC", "", buffer + 1, size - 1, instr); 2019 | case 0x1A: 2020 | return s7_decode_byte("L", "MD ", buffer + 1, size - 1, instr); 2021 | case 0x1B: 2022 | return s7_decode_byte("T", "MD ", buffer + 1, size - 1, instr); 2023 | case 0x1C: 2024 | return s7_decode_byte("SE", "T ", buffer + 1, size - 1, instr); 2025 | case 0x1D: 2026 | return s7_decode_byte("CC", "FC ", buffer + 1, size - 1, instr); 2027 | case 0x20: 2028 | if (buffer[1] == 0x0A) { 2029 | return s7_decode_200A(buffer + 1, size - 1, instr); 2030 | } else { 2031 | return s7_decode_byte("OPN", "DB ", buffer + 1, size - 1, instr); 2032 | } 2033 | case 0x21: 2034 | return s7_decode_cmp("I", buffer + 1, size - 1, instr); 2035 | case 0x24: 2036 | return s7_decode_byte("SD", "T ", buffer + 1, size - 1, instr); 2037 | case 0x28: 2038 | return s7_decode_byte("L", "B#16#", buffer + 1, size - 1, instr); 2039 | case 0x29: 2040 | if (buffer[1] < 0x10) { 2041 | return s7_decode_byte("SLD", "", buffer + 1, size - 1, instr); 2042 | } else { 2043 | return -1; 2044 | } 2045 | case 0x2C: 2046 | return s7_decode_byte("SS", "T ", buffer + 1, size - 1, instr); 2047 | case 0x30: 2048 | return s7_decode_lit16(buffer + 1, size - 1, instr); 2049 | case 0x31: 2050 | return s7_decode_cmp("R", buffer + 1, size - 1, instr); 2051 | case 0x34: 2052 | return s7_decode_byte("SP", "T ", buffer + 1, size - 1, instr); 2053 | case 0x38: 2054 | return s7_decode_lit32(buffer + 1, size - 1, instr); 2055 | case 0x39: 2056 | return s7_decode_cmp("D", buffer + 1, size - 1, instr); 2057 | case 0x3C: 2058 | return s7_decode_byte("R", "T ", buffer + 1, size - 1, instr); 2059 | case 0x3D: 2060 | return s7_decode_byte("UC", "FC ", buffer + 1, size - 1, instr); 2061 | case 0x41: 2062 | return s7_decode_bitlogic("AW", "=", NULL, buffer + 1, size - 1, instr); 2063 | case 0x42: 2064 | return s7_decode_byte("L", "C ", buffer + 1, size - 1, instr); 2065 | case 0x44: 2066 | return s7_decode_byte("FR", "C ", buffer + 1, size - 1, instr); 2067 | case 0x49: 2068 | return s7_decode_bitlogic("OW", "FP", "FN", buffer + 1, size - 1, instr); 2069 | case 0x4A: 2070 | return s7_decode_byte_signed("L", "IB", "QB", "", buffer + 1, size - 1, instr); 2071 | case 0x4B: 2072 | return s7_decode_byte_signed("T", "IB", "QB", "", buffer + 1, size - 1, instr); 2073 | case 0x4C: 2074 | return s7_decode_byte("LC", "C ", buffer + 1, size - 1, instr); 2075 | case 0x51: 2076 | return s7_decode_bitlogic_mem("XOW", false, "A", "O", "AN", "ON", buffer + 1, size - 1, instr); 2077 | case 0x52: 2078 | return s7_decode_byte_signed("L", "IW", "QW", "", buffer + 1, size - 1, instr); 2079 | case 0x53: 2080 | return s7_decode_byte_signed("T", "IW", "QW", "", buffer + 1, size - 1, instr); 2081 | case 0x54: 2082 | return s7_decode_byte("CD", "C ", buffer + 1, size - 1, instr); 2083 | case 0x55: 2084 | return s7_decode_byte("CC", "FB ", buffer + 1, size - 1, instr); 2085 | case 0x58: 2086 | return s7_decode_bitlogic_mem("+", true, "X", "S", "XN", "R", buffer + 1, size - 1, instr); 2087 | case 0x59: 2088 | return s7_decode_bitlogic_mem("-I", false, "=", "FP", NULL, "FN", buffer + 1, size - 1, instr); 2089 | case 0x5A: 2090 | return s7_decode_byte_signed("L", "ID", "QD", "", buffer + 1, size - 1, instr); 2091 | case 0x5B: 2092 | return s7_decode_byte_signed("T", "ID", "QD", "", buffer + 1, size - 1, instr); 2093 | case 0x5C: 2094 | return s7_decode_byte("S", "C ", buffer + 1, size - 1, instr); 2095 | case 0x60: 2096 | if (buffer[1] == 0x05 && size > 5) { 2097 | st32_t value = (st32_t)s7_ut32(buffer + 2); 2098 | snprintf(instr->assembly, sizeof(instr->assembly), "+ L#%d", value); 2099 | return 6; 2100 | } else { 2101 | const s7_static_t ops[] = { 2102 | { 0x00, "/I" }, 2103 | { 0x01, "MOD" }, 2104 | { 0x02, "ABS" }, 2105 | { 0x03, "/R" }, 2106 | { 0x04, "*I" }, 2107 | { 0x06, "NEGR" }, 2108 | { 0x07, "*R" }, 2109 | { 0x08, "ENT" }, 2110 | { 0x09, "-D" }, 2111 | { 0x0A, "*D" }, 2112 | { 0x0B, "-R" }, 2113 | { 0x0D, "+D" }, 2114 | { 0x0E, "/D" }, 2115 | { 0x0F, "+R" }, 2116 | { 0x10, "SIN" }, 2117 | { 0x11, "COS" }, 2118 | { 0x12, "TAN" }, 2119 | { 0x13, "LN" }, 2120 | { 0x14, "SQRT" }, 2121 | { 0x18, "ASIN" }, 2122 | { 0x19, "ACOS" }, 2123 | { 0x1A, "ATAN" }, 2124 | { 0x1B, "EXP" }, 2125 | { 0x1C, "SQR" }, 2126 | { 0, NULL } 2127 | }; 2128 | return s7_decode_static(ops, buffer + 1, size - 1, instr); 2129 | } 2130 | case 0x61: 2131 | if (buffer[1] < 0x10) { 2132 | return s7_decode_4bit("SLW", false, buffer + 1, size - 1, instr); 2133 | } else { 2134 | return -1; 2135 | } 2136 | case 0x64: 2137 | if (buffer[1] <= 32) { 2138 | return s7_decode_byte("RLD", "", buffer + 1, size - 1, instr); 2139 | } else { 2140 | return -1; 2141 | } 2142 | case 0x65: { 2143 | const s7_static_t ops[] = { 2144 | { 0x00, "BE" }, 2145 | { 0x01, "BEU" }, 2146 | { 0, NULL } 2147 | }; 2148 | int ret = s7_decode_static(ops, buffer + 1, size - 1, instr); 2149 | if (ret > 0) { 2150 | instr->is_return = true; 2151 | } 2152 | return ret; 2153 | } 2154 | case 0x68: 2155 | if (size > 5) { 2156 | ut32_t value = s7_ut32(buffer + 2); 2157 | switch (buffer[1]) { 2158 | case 0x36: 2159 | snprintf(instr->assembly, sizeof(instr->assembly), "AD DW#16#%x", value); 2160 | return 6; 2161 | case 0x46: 2162 | snprintf(instr->assembly, sizeof(instr->assembly), "OD DW#16#%x", value); 2163 | return 6; 2164 | case 0x56: 2165 | snprintf(instr->assembly, sizeof(instr->assembly), "XOD DW#16#%x", value); 2166 | return 6; 2167 | default: 2168 | break; 2169 | } 2170 | } else if (size > 3) { 2171 | ut16_t value = s7_ut16(buffer + 2); 2172 | switch (buffer[1]) { 2173 | case 0x34: 2174 | snprintf(instr->assembly, sizeof(instr->assembly), "AW W#16#%x", value); 2175 | return 4; 2176 | case 0x44: 2177 | snprintf(instr->assembly, sizeof(instr->assembly), "OW W#16#%x", value); 2178 | return 4; 2179 | case 0x54: 2180 | snprintf(instr->assembly, sizeof(instr->assembly), "XOW W#16#%x", value); 2181 | return 4; 2182 | default: 2183 | break; 2184 | } 2185 | } 2186 | if ((buffer[1] & 0x0F) == 0x01) { 2187 | return s7_decode_4bit("SSI", true, buffer + 1, size - 1, instr); 2188 | } else { 2189 | const s7_static_t ops[] = { 2190 | { 0x06, "DTR" }, 2191 | { 0x07, "NEGD" }, 2192 | { 0x08, "ITB" }, 2193 | { 0x0A, "DTB" }, 2194 | { 0x0C, "BTI" }, 2195 | { 0x0E, "BTD" }, 2196 | { 0x0D, "INVD" }, 2197 | { 0x12, "SLW" }, 2198 | { 0x13, "SLD" }, 2199 | { 0x17, "RLD" }, 2200 | { 0x18, "RLDA" }, 2201 | { 0x1A, "CAW" }, 2202 | { 0x1B, "CAD" }, 2203 | { 0x1C, "CLR" }, 2204 | { 0x1D, "SET" }, 2205 | { 0x1E, "ITD" }, 2206 | { 0x22, "SRW" }, 2207 | { 0x23, "SRD" }, 2208 | { 0x24, "SSI" }, 2209 | { 0x25, "SSD" }, 2210 | { 0x27, "RRD" }, 2211 | { 0x28, "RRDA" }, 2212 | { 0x2C, "SAVE" }, 2213 | { 0x2D, "NOT" }, 2214 | { 0x2E, "PUSH" }, 2215 | { 0x37, "AD" }, 2216 | { 0x3A, "MCRA" }, 2217 | { 0x3B, "MCRD" }, 2218 | { 0x3C, "MCR(" }, 2219 | { 0x3D, ")MCR" }, 2220 | { 0x3E, "POP" }, 2221 | { 0x47, "OD" }, 2222 | { 0x4E, "LEAVE" }, 2223 | { 0x57, "XOD" }, 2224 | { 0x5C, "RND" }, 2225 | { 0x5D, "RND-" }, 2226 | { 0x5E, "RND+" }, 2227 | { 0x5F, "TRUNC" }, 2228 | { 0, NULL } 2229 | }; 2230 | return s7_decode_static(ops, buffer + 1, size - 1, instr); 2231 | } 2232 | return -1; 2233 | case 0x69: 2234 | if (buffer[1] < 0x10) { 2235 | return s7_decode_4bit("SRW", false, buffer + 1, size - 1, instr); 2236 | } else { 2237 | return -1; 2238 | } 2239 | case 0x6C: 2240 | return s7_decode_byte("CU", "C ", buffer + 1, size - 1, instr); 2241 | case 0x70: 2242 | if (buffer[1] == 0x08) { 2243 | return s7_decode_jump("LOOP", addr, buffer + 1, size - 1, instr); 2244 | } else if (buffer[1] == 0x09) { 2245 | return s7_decode_jump("JL", addr, buffer + 1, size - 1, instr); 2246 | } else if (buffer[1] == 0x0B) { 2247 | return s7_decode_jump("JU", addr, buffer + 1, size - 1, instr); 2248 | } else { 2249 | const s7_static_t ops[] = { 2250 | { 0x02, "TAK" }, 2251 | { 0x06, "L STW" }, 2252 | { 0x07, "T STW" }, 2253 | { 0, NULL } 2254 | }; 2255 | return s7_decode_static(ops, buffer + 1, size - 1, instr); 2256 | } 2257 | case 0x71: 2258 | if (buffer[1] < 0x10) { 2259 | return s7_decode_4bit("SSD", false, buffer + 1, size - 1, instr); 2260 | } else { 2261 | return -1; 2262 | } 2263 | case 0x74: 2264 | return s7_decode_byte("RRD", "", buffer + 1, size - 1, instr); 2265 | case 0x75: 2266 | return s7_decode_byte("UC", "FB ", buffer + 1, size - 1, instr); 2267 | case 0x79: 2268 | return s7_decode_79(buffer + 1, size - 1, instr); 2269 | case 0x7C: 2270 | return s7_decode_byte("R", "C ", buffer + 1, size - 1, instr); 2271 | case 0x7E: 2272 | return s7_decode_7E(buffer + 1, size - 1, instr); 2273 | case 0x80: 2274 | return s7_decode_byte_s("A M", ".0", buffer + 1, size - 1, instr); 2275 | case 0x81: 2276 | return s7_decode_byte_s("A M", ".1", buffer + 1, size - 1, instr); 2277 | case 0x82: 2278 | return s7_decode_byte_s("A M", ".2", buffer + 1, size - 1, instr); 2279 | case 0x83: 2280 | return s7_decode_byte_s("A M", ".3", buffer + 1, size - 1, instr); 2281 | case 0x84: 2282 | return s7_decode_byte_s("A M", ".4", buffer + 1, size - 1, instr); 2283 | case 0x85: 2284 | return s7_decode_byte_s("A M", ".5", buffer + 1, size - 1, instr); 2285 | case 0x86: 2286 | return s7_decode_byte_s("A M", ".6", buffer + 1, size - 1, instr); 2287 | case 0x87: 2288 | return s7_decode_byte_s("A M", ".7", buffer + 1, size - 1, instr); 2289 | case 0x88: 2290 | return s7_decode_byte_s("O M", ".0", buffer + 1, size - 1, instr); 2291 | case 0x89: 2292 | return s7_decode_byte_s("O M", ".1", buffer + 1, size - 1, instr); 2293 | case 0x8A: 2294 | return s7_decode_byte_s("O M", ".2", buffer + 1, size - 1, instr); 2295 | case 0x8B: 2296 | return s7_decode_byte_s("O M", ".3", buffer + 1, size - 1, instr); 2297 | case 0x8C: 2298 | return s7_decode_byte_s("O M", ".4", buffer + 1, size - 1, instr); 2299 | case 0x8D: 2300 | return s7_decode_byte_s("O M", ".5", buffer + 1, size - 1, instr); 2301 | case 0x8E: 2302 | return s7_decode_byte_s("O M", ".6", buffer + 1, size - 1, instr); 2303 | case 0x8F: 2304 | return s7_decode_byte_s("O M", ".7", buffer + 1, size - 1, instr); 2305 | case 0x90: 2306 | return s7_decode_byte_s("S M", ".0", buffer + 1, size - 1, instr); 2307 | case 0x91: 2308 | return s7_decode_byte_s("S M", ".1", buffer + 1, size - 1, instr); 2309 | case 0x92: 2310 | return s7_decode_byte_s("S M", ".2", buffer + 1, size - 1, instr); 2311 | case 0x93: 2312 | return s7_decode_byte_s("S M", ".3", buffer + 1, size - 1, instr); 2313 | case 0x94: 2314 | return s7_decode_byte_s("S M", ".4", buffer + 1, size - 1, instr); 2315 | case 0x95: 2316 | return s7_decode_byte_s("S M", ".5", buffer + 1, size - 1, instr); 2317 | case 0x96: 2318 | return s7_decode_byte_s("S M", ".6", buffer + 1, size - 1, instr); 2319 | case 0x97: 2320 | return s7_decode_byte_s("S M", ".7", buffer + 1, size - 1, instr); 2321 | case 0x98: 2322 | return s7_decode_byte_s("= M", ".0", buffer + 1, size - 1, instr); 2323 | case 0x99: 2324 | return s7_decode_byte_s("= M", ".1", buffer + 1, size - 1, instr); 2325 | case 0x9A: 2326 | return s7_decode_byte_s("= M", ".2", buffer + 1, size - 1, instr); 2327 | case 0x9B: 2328 | return s7_decode_byte_s("= M", ".3", buffer + 1, size - 1, instr); 2329 | case 0x9C: 2330 | return s7_decode_byte_s("= M", ".4", buffer + 1, size - 1, instr); 2331 | case 0x9D: 2332 | return s7_decode_byte_s("= M", ".5", buffer + 1, size - 1, instr); 2333 | case 0x9E: 2334 | return s7_decode_byte_s("= M", ".6", buffer + 1, size - 1, instr); 2335 | case 0x9F: 2336 | return s7_decode_byte_s("= M", ".7", buffer + 1, size - 1, instr); 2337 | case 0xA0: 2338 | return s7_decode_byte_s("AN M", ".0", buffer + 1, size - 1, instr); 2339 | case 0xA1: 2340 | return s7_decode_byte_s("AN M", ".1", buffer + 1, size - 1, instr); 2341 | case 0xA2: 2342 | return s7_decode_byte_s("AN M", ".2", buffer + 1, size - 1, instr); 2343 | case 0xA3: 2344 | return s7_decode_byte_s("AN M", ".3", buffer + 1, size - 1, instr); 2345 | case 0xA4: 2346 | return s7_decode_byte_s("AN M", ".4", buffer + 1, size - 1, instr); 2347 | case 0xA5: 2348 | return s7_decode_byte_s("AN M", ".5", buffer + 1, size - 1, instr); 2349 | case 0xA6: 2350 | return s7_decode_byte_s("AN M", ".6", buffer + 1, size - 1, instr); 2351 | case 0xA7: 2352 | return s7_decode_byte_s("AN M", ".7", buffer + 1, size - 1, instr); 2353 | case 0xA8: 2354 | return s7_decode_byte_s("ON M", ".0", buffer + 1, size - 1, instr); 2355 | case 0xA9: 2356 | return s7_decode_byte_s("ON M", ".1", buffer + 1, size - 1, instr); 2357 | case 0xAA: 2358 | return s7_decode_byte_s("ON M", ".2", buffer + 1, size - 1, instr); 2359 | case 0xAB: 2360 | return s7_decode_byte_s("ON M", ".3", buffer + 1, size - 1, instr); 2361 | case 0xAC: 2362 | return s7_decode_byte_s("ON M", ".4", buffer + 1, size - 1, instr); 2363 | case 0xAD: 2364 | return s7_decode_byte_s("ON M", ".5", buffer + 1, size - 1, instr); 2365 | case 0xAE: 2366 | return s7_decode_byte_s("ON M", ".6", buffer + 1, size - 1, instr); 2367 | case 0xAF: 2368 | return s7_decode_byte_s("ON M", ".7", buffer + 1, size - 1, instr); 2369 | case 0xB0: 2370 | return s7_decode_byte_s("R M", ".0", buffer + 1, size - 1, instr); 2371 | case 0xB1: 2372 | return s7_decode_byte_s("R M", ".1", buffer + 1, size - 1, instr); 2373 | case 0xB2: 2374 | return s7_decode_byte_s("R M", ".2", buffer + 1, size - 1, instr); 2375 | case 0xB3: 2376 | return s7_decode_byte_s("R M", ".3", buffer + 1, size - 1, instr); 2377 | case 0xB4: 2378 | return s7_decode_byte_s("R M", ".4", buffer + 1, size - 1, instr); 2379 | case 0xB5: 2380 | return s7_decode_byte_s("R M", ".5", buffer + 1, size - 1, instr); 2381 | case 0xB6: 2382 | return s7_decode_byte_s("R M", ".6", buffer + 1, size - 1, instr); 2383 | case 0xB7: 2384 | return s7_decode_byte_s("R M", ".7", buffer + 1, size - 1, instr); 2385 | case 0xB8: 2386 | return s7_decode_byte("A", "C ", buffer + 1, size - 1, instr); 2387 | case 0xB9: 2388 | return s7_decode_byte("O", "C ", buffer + 1, size - 1, instr); 2389 | case 0xBC: 2390 | return s7_decode_byte("AN", "C ", buffer + 1, size - 1, instr); 2391 | case 0xBD: 2392 | return s7_decode_byte("ON", "C ", buffer + 1, size - 1, instr); 2393 | case 0xBA: 2394 | if ((buffer[1] > 0x66 && buffer[1] < 0xB0) || buffer[1] > 0xE6) { 2395 | return -1; 2396 | } else { 2397 | return s7_decode_mem("A(", "L", "T", types_b, types_b, buffer + 1, size - 1, instr); 2398 | } 2399 | case 0xBB: 2400 | return s7_decode_mem("O(", "L", "T", types_w, types_d, buffer + 1, size - 1, instr); 2401 | case 0xBE: 2402 | return s7_decode_BE(buffer + 1, size - 1, instr); 2403 | case 0xBF: 2404 | return s7_decode_BF(buffer + 1, size - 1, instr); 2405 | case 0xC0: 2406 | return s7_decode_byte_signed("A", "I", "Q", ".0", buffer + 1, size - 1, instr); 2407 | case 0xC1: 2408 | return s7_decode_byte_signed("A", "I", "Q", ".1", buffer + 1, size - 1, instr); 2409 | case 0xC2: 2410 | return s7_decode_byte_signed("A", "I", "Q", ".2", buffer + 1, size - 1, instr); 2411 | case 0xC3: 2412 | return s7_decode_byte_signed("A", "I", "Q", ".3", buffer + 1, size - 1, instr); 2413 | case 0xC4: 2414 | return s7_decode_byte_signed("A", "I", "Q", ".4", buffer + 1, size - 1, instr); 2415 | case 0xC5: 2416 | return s7_decode_byte_signed("A", "I", "Q", ".5", buffer + 1, size - 1, instr); 2417 | case 0xC6: 2418 | return s7_decode_byte_signed("A", "I", "Q", ".6", buffer + 1, size - 1, instr); 2419 | case 0xC7: 2420 | return s7_decode_byte_signed("A", "I", "Q", ".7", buffer + 1, size - 1, instr); 2421 | case 0xC8: 2422 | return s7_decode_byte_signed("O", "I", "Q", ".0", buffer + 1, size - 1, instr); 2423 | case 0xC9: 2424 | return s7_decode_byte_signed("O", "I", "Q", ".1", buffer + 1, size - 1, instr); 2425 | case 0xCA: 2426 | return s7_decode_byte_signed("O", "I", "Q", ".2", buffer + 1, size - 1, instr); 2427 | case 0xCB: 2428 | return s7_decode_byte_signed("O", "I", "Q", ".3", buffer + 1, size - 1, instr); 2429 | case 0xCC: 2430 | return s7_decode_byte_signed("O", "I", "Q", ".4", buffer + 1, size - 1, instr); 2431 | case 0xCD: 2432 | return s7_decode_byte_signed("O", "I", "Q", ".5", buffer + 1, size - 1, instr); 2433 | case 0xCE: 2434 | return s7_decode_byte_signed("O", "I", "Q", ".6", buffer + 1, size - 1, instr); 2435 | case 0xCF: 2436 | return s7_decode_byte_signed("O", "I", "Q", ".7", buffer + 1, size - 1, instr); 2437 | case 0xD0: 2438 | return s7_decode_byte_signed("S", "I", "Q", ".0", buffer + 1, size - 1, instr); 2439 | case 0xD1: 2440 | return s7_decode_byte_signed("S", "I", "Q", ".1", buffer + 1, size - 1, instr); 2441 | case 0xD2: 2442 | return s7_decode_byte_signed("S", "I", "Q", ".2", buffer + 1, size - 1, instr); 2443 | case 0xD3: 2444 | return s7_decode_byte_signed("S", "I", "Q", ".3", buffer + 1, size - 1, instr); 2445 | case 0xD4: 2446 | return s7_decode_byte_signed("S", "I", "Q", ".4", buffer + 1, size - 1, instr); 2447 | case 0xD5: 2448 | return s7_decode_byte_signed("S", "I", "Q", ".5", buffer + 1, size - 1, instr); 2449 | case 0xD6: 2450 | return s7_decode_byte_signed("S", "I", "Q", ".6", buffer + 1, size - 1, instr); 2451 | case 0xD7: 2452 | return s7_decode_byte_signed("S", "I", "Q", ".7", buffer + 1, size - 1, instr); 2453 | case 0xD8: 2454 | return s7_decode_byte_signed("=", "I", "Q", ".0", buffer + 1, size - 1, instr); 2455 | case 0xD9: 2456 | return s7_decode_byte_signed("=", "I", "Q", ".1", buffer + 1, size - 1, instr); 2457 | case 0xDA: 2458 | return s7_decode_byte_signed("=", "I", "Q", ".2", buffer + 1, size - 1, instr); 2459 | case 0xDB: 2460 | return s7_decode_byte_signed("=", "I", "Q", ".3", buffer + 1, size - 1, instr); 2461 | case 0xDC: 2462 | return s7_decode_byte_signed("=", "I", "Q", ".4", buffer + 1, size - 1, instr); 2463 | case 0xDD: 2464 | return s7_decode_byte_signed("=", "I", "Q", ".5", buffer + 1, size - 1, instr); 2465 | case 0xDE: 2466 | return s7_decode_byte_signed("=", "I", "Q", ".6", buffer + 1, size - 1, instr); 2467 | case 0xDF: 2468 | return s7_decode_byte_signed("=", "I", "Q", ".7", buffer + 1, size - 1, instr); 2469 | case 0xE0: 2470 | return s7_decode_byte_signed("AN", "I", "Q", ".0", buffer + 1, size - 1, instr); 2471 | case 0xE1: 2472 | return s7_decode_byte_signed("AN", "I", "Q", ".1", buffer + 1, size - 1, instr); 2473 | case 0xE2: 2474 | return s7_decode_byte_signed("AN", "I", "Q", ".2", buffer + 1, size - 1, instr); 2475 | case 0xE3: 2476 | return s7_decode_byte_signed("AN", "I", "Q", ".3", buffer + 1, size - 1, instr); 2477 | case 0xE4: 2478 | return s7_decode_byte_signed("AN", "I", "Q", ".4", buffer + 1, size - 1, instr); 2479 | case 0xE5: 2480 | return s7_decode_byte_signed("AN", "I", "Q", ".5", buffer + 1, size - 1, instr); 2481 | case 0xE6: 2482 | return s7_decode_byte_signed("AN", "I", "Q", ".6", buffer + 1, size - 1, instr); 2483 | case 0xE7: 2484 | return s7_decode_byte_signed("AN", "I", "Q", ".7", buffer + 1, size - 1, instr); 2485 | case 0xE8: 2486 | return s7_decode_byte_signed("ON", "I", "Q", ".0", buffer + 1, size - 1, instr); 2487 | case 0xE9: 2488 | return s7_decode_byte_signed("ON", "I", "Q", ".1", buffer + 1, size - 1, instr); 2489 | case 0xEA: 2490 | return s7_decode_byte_signed("ON", "I", "Q", ".2", buffer + 1, size - 1, instr); 2491 | case 0xEB: 2492 | return s7_decode_byte_signed("ON", "I", "Q", ".3", buffer + 1, size - 1, instr); 2493 | case 0xEC: 2494 | return s7_decode_byte_signed("ON", "I", "Q", ".4", buffer + 1, size - 1, instr); 2495 | case 0xED: 2496 | return s7_decode_byte_signed("ON", "I", "Q", ".5", buffer + 1, size - 1, instr); 2497 | case 0xEE: 2498 | return s7_decode_byte_signed("ON", "I", "Q", ".6", buffer + 1, size - 1, instr); 2499 | case 0xEF: 2500 | return s7_decode_byte_signed("ON", "I", "Q", ".7", buffer + 1, size - 1, instr); 2501 | case 0xF0: 2502 | return s7_decode_byte_signed("R", "I", "Q", ".0", buffer + 1, size - 1, instr); 2503 | case 0xF1: 2504 | return s7_decode_byte_signed("R", "I", "Q", ".1", buffer + 1, size - 1, instr); 2505 | case 0xF2: 2506 | return s7_decode_byte_signed("R", "I", "Q", ".2", buffer + 1, size - 1, instr); 2507 | case 0xF3: 2508 | return s7_decode_byte_signed("R", "I", "Q", ".3", buffer + 1, size - 1, instr); 2509 | case 0xF4: 2510 | return s7_decode_byte_signed("R", "I", "Q", ".4", buffer + 1, size - 1, instr); 2511 | case 0xF5: 2512 | return s7_decode_byte_signed("R", "I", "Q", ".5", buffer + 1, size - 1, instr); 2513 | case 0xF6: 2514 | return s7_decode_byte_signed("R", "I", "Q", ".6", buffer + 1, size - 1, instr); 2515 | case 0xF7: 2516 | return s7_decode_byte_signed("R", "I", "Q", ".7", buffer + 1, size - 1, instr); 2517 | case 0xF8: 2518 | return s7_decode_byte("A", "T ", buffer + 1, size - 1, instr); 2519 | case 0xF9: 2520 | return s7_decode_byte("O", "T ", buffer + 1, size - 1, instr); 2521 | case 0xFB: 2522 | return s7_decode_FB(buffer + 1, size - 1, instr); 2523 | case 0xFC: 2524 | return s7_decode_byte("AN", "T ", buffer + 1, size - 1, instr); 2525 | case 0xFD: 2526 | return s7_decode_byte("ON", "T ", buffer + 1, size - 1, instr); 2527 | case 0xFE: 2528 | return s7_decode_FE(buffer + 1, size - 1, instr); 2529 | case 0xFF: 2530 | return s7_decode_FF(addr, buffer + 1, size - 1, instr); 2531 | default: 2532 | break; 2533 | } 2534 | return -1; 2535 | } 2536 | --------------------------------------------------------------------------------