├── .gitignore
├── LICENSE.md
├── README.md
├── VTIL-Common.licenseheader
├── VTIL-Common.sln
├── VTIL-Common.vcxproj
├── VTIL-Common.vcxproj.filters
├── amd64
├── assembler.cpp
├── assembler.hpp
├── disassembly.cpp
├── disassembly.hpp
├── register_details.cpp
└── register_details.hpp
├── includes
└── vtil
│ ├── amd64
│ ├── common
│ ├── io
│ ├── math
│ ├── query
│ ├── utility
│ └── vtil
├── io
├── asserts.hpp
├── formatting.hpp
├── logger.cpp
└── logger.hpp
├── math
├── bitwise.hpp
├── operable.hpp
├── operators.cpp
└── operators.hpp
├── query
├── fixed_iterator.hpp
├── query_descriptor.hpp
├── range_iterator.hpp
├── range_iterator_contract.hpp
├── recursive_view.hpp
└── view.hpp
└── util
├── concept.hpp
├── copy_on_write.hpp
├── critical_section.cpp
├── critical_section.hpp
├── fnv128.hpp
├── fnv64.hpp
├── hashable.hpp
├── priority_list.hpp
├── reducable.hpp
├── stack_container.hpp
├── variant.cpp
└── variant.hpp
/.gitignore:
--------------------------------------------------------------------------------
1 | *.db
2 | *.ipch
3 | *.opendb
4 | *.user
5 | *.log
6 | *.exe
7 | *.tlog
8 | *.obj
9 | *.exp
10 | *.pdb
11 | *.lib
12 | *.suo
13 | *.ilk
14 | *.db-shm
15 | *.db-wal
16 | .vs/
17 | x64/Debug/
18 | x64/Release/
19 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 |
2 | Copyright (c) 2020, Can Bölük
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | * Neither the name of [project] nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VTIL
2 |
3 | ## 1) What is VTIL?
4 | VTIL (Virtual-machine Translation Intermediate Language) Project is a set of tools that can be used for binary deobfuscation and devirtualization.
5 |
6 | ## 2) What is this repostiory?
7 |
8 | This repository contains the IL definition and any generic helpers and wrappers we use across the VTIL toolchain.
9 |
10 | Components are likely incomplete as initial release is not done yet, and documentation and FAQ will be on this README file and the organization website once they're done.
11 |
12 | Until the initial release you can keep up to date with the VTIL project by checking my [personal twitter account](https://twitter.com/_can1357) or the VTIL website [vtil.org](https://vtil.org/).
13 |
14 | ## 3) What happened to the previous repository?
15 | All the contents of that repository will be eventually merged into this organization account once they are needed, in one way or another, likely next week.
--------------------------------------------------------------------------------
/VTIL-Common.licenseheader:
--------------------------------------------------------------------------------
1 | extensions: .hpp .cpp .h .c
2 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are met:
7 | //
8 | // 1. Redistributions of source code must retain the above copyright notice,
9 | // this list of conditions and the following disclaimer.
10 | // 2. Redistributions in binary form must reproduce the above copyright
11 | // notice, this list of conditions and the following disclaimer in the
12 | // documentation and/or other materials provided with the distribution.
13 | // 3. Neither the name of mosquitto nor the names of its
14 | // contributors may be used to endorse or promote products derived from
15 | // this software without specific prior written permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | // POSSIBILITY OF SUCH DAMAGE.
28 | //
--------------------------------------------------------------------------------
/VTIL-Common.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29709.97
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VTIL-Common", "VTIL-Common.vcxproj", "{EC6B8F7F-730C-4086-B143-4664CC16DF8F}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Release|x64 = Release|x64
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {EC6B8F7F-730C-4086-B143-4664CC16DF8F}.Debug|x64.ActiveCfg = Debug|x64
15 | {EC6B8F7F-730C-4086-B143-4664CC16DF8F}.Debug|x64.Build.0 = Debug|x64
16 | {EC6B8F7F-730C-4086-B143-4664CC16DF8F}.Release|x64.ActiveCfg = Release|x64
17 | {EC6B8F7F-730C-4086-B143-4664CC16DF8F}.Release|x64.Build.0 = Release|x64
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {7152B430-9587-4928-BBF8-343854EA2DA0}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/VTIL-Common.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 | 16.0
15 | {EC6B8F7F-730C-4086-B143-4664CC16DF8F}
16 | Win32Proj
17 | VTILCommon
18 | 10.0
19 |
20 |
21 |
22 | StaticLibrary
23 | true
24 | v142
25 | Unicode
26 |
27 |
28 | StaticLibrary
29 | false
30 | v142
31 | true
32 | Unicode
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | true
48 | $(SolutionDir)..\Capstone\include;$(SolutionDir)..\Keystone\include;$(IncludePath)
49 | $(SolutionDir)..\Keystone\llvm\lib\Debug;$(SolutionDir)..\Capstone\msvc\x64\Release;$(LibraryPath)
50 | $(ProjectDir)$(Platform)\$(Configuration)\
51 |
52 |
53 | false
54 | $(SolutionDir)..\Capstone\include;$(SolutionDir)..\Keystone\include;$(IncludePath)
55 | $(SolutionDir)..\Keystone\llvm\lib\Release;$(SolutionDir)..\Capstone\msvc\x64\Release;$(LibraryPath)
56 | $(ProjectDir)$(Platform)\$(Configuration)\
57 |
58 |
59 |
60 | NotUsing
61 | Level3
62 | true
63 | _DEBUG;_LIB;%(PreprocessorDefinitions)
64 | true
65 |
66 |
67 | stdcpplatest
68 |
69 |
70 |
71 |
72 | Windows
73 | true
74 |
75 |
76 | keystone.lib;capstone.lib;
77 |
78 |
79 |
80 |
81 | NotUsing
82 | Level3
83 | true
84 | true
85 | true
86 | NDEBUG;_LIB;%(PreprocessorDefinitions)
87 | true
88 | pch.h
89 | stdcpplatest
90 |
91 |
92 |
93 |
94 | Windows
95 | true
96 | true
97 | true
98 |
99 |
100 | keystone.lib;capstone.lib;
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/VTIL-Common.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {14333603-a637-4356-854a-db631a744d42}
6 |
7 |
8 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
9 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
10 |
11 |
12 | {cb6f5bfd-fdca-47fe-bbb7-e91d8e5ba642}
13 |
14 |
15 | {dbf4733d-3814-4218-9474-cf4b4e3c5719}
16 |
17 |
18 | {e5d9bf65-c2c0-4dcf-aa87-65a7059e4e90}
19 |
20 |
21 | {226c5e44-6592-44d0-adb0-31369963cb86}
22 |
23 |
24 | {91e43426-e8a8-4753-8d61-374c3c62f081}
25 |
26 |
27 |
28 |
29 | amd64
30 |
31 |
32 | amd64\Core
33 |
34 |
35 | amd64\Core
36 |
37 |
38 | I/O
39 |
40 |
41 | I/O
42 |
43 |
44 | I/O
45 |
46 |
47 | Includes
48 |
49 |
50 | Includes
51 |
52 |
53 | Includes
54 |
55 |
56 | Math
57 |
58 |
59 | Math
60 |
61 |
62 | Math
63 |
64 |
65 | Includes
66 |
67 |
68 | Utility
69 |
70 |
71 | Includes
72 |
73 |
74 | Queries
75 |
76 |
77 | Queries
78 |
79 |
80 | Queries
81 |
82 |
83 | Queries
84 |
85 |
86 | Queries
87 |
88 |
89 | Includes
90 |
91 |
92 | Queries
93 |
94 |
95 | Utility
96 |
97 |
98 | Utility
99 |
100 |
101 | Utility
102 |
103 |
104 | Utility
105 |
106 |
107 | Utility
108 |
109 |
110 | Utility
111 |
112 |
113 | Utility
114 |
115 |
116 | Utility
117 |
118 |
119 | Utility
120 |
121 |
122 |
123 |
124 | amd64
125 |
126 |
127 | amd64\Core
128 |
129 |
130 | amd64\Core
131 |
132 |
133 | I/O
134 |
135 |
136 | Math
137 |
138 |
139 | Utility
140 |
141 |
142 | Utility
143 |
144 |
145 |
146 |
147 |
148 | Includes
149 |
150 |
151 |
--------------------------------------------------------------------------------
/amd64/assembler.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 |
29 | // Furthermore, the following pieces of software have additional copyrights
30 | // licenses, and/or restrictions:
31 | //
32 | // |--------------------------------------------------------------------------|
33 | // | File name | Link for further information |
34 | // |-------------------------|------------------------------------------------|
35 | // | amd64/* | https://github.com/aquynh/capstone/ |
36 | // | | https://github.com/keystone-engine/keystone/ |
37 | // |--------------------------------------------------------------------------|
38 | //
39 | #include "assembler.hpp"
40 | #include
41 |
42 | namespace keystone
43 | {
44 | ks_struct* get_handle()
45 | {
46 | // Keystone engine is not created until the first call.
47 | //
48 | static ks_engine* handle = [ ] ()
49 | {
50 | ks_engine* handle;
51 | if ( ks_open( KS_ARCH_X86, KS_MODE_64, &handle ) != KS_ERR_OK )
52 | throw std::exception( "Failed to create the Keystone engine!" );
53 | return handle;
54 | }( );
55 | return handle;
56 | }
57 |
58 | std::vector assemble( const std::string& src, uint64_t va )
59 | {
60 | // Assemble the given instruction in text format.
61 | // - (Not too sure why I have to do the .code64; hack, but won't question.)
62 | //
63 | size_t size;
64 | size_t count;
65 | unsigned char* encode = nullptr;
66 | if ( ks_asm( get_handle(), ( ".code64;" + src ).data(), va, &encode, &size, &count ) )
67 | {
68 | // Free (if relevant) and return on failure.
69 | //
70 | if ( encode ) ks_free( encode );
71 | return {};
72 | }
73 |
74 | // Convert to a vector of bytes, free the encoding and return it.
75 | //
76 | std::vector output = { encode, encode + size };
77 | ks_free( encode );
78 | return output;
79 | }
80 | };
--------------------------------------------------------------------------------
/amd64/assembler.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 |
29 | // Furthermore, the following pieces of software have additional copyrights
30 | // licenses, and/or restrictions:
31 | //
32 | // |--------------------------------------------------------------------------|
33 | // | File name | Link for further information |
34 | // |-------------------------|------------------------------------------------|
35 | // | amd64/* | https://github.com/aquynh/capstone/ |
36 | // | | https://github.com/keystone-engine/keystone/ |
37 | // |--------------------------------------------------------------------------|
38 | //
39 | #pragma once
40 | #include
41 | #include
42 |
43 | // Simple wrapper around Keystone disassembler.
44 | //
45 | struct ks_struct;
46 | namespace keystone
47 | {
48 | ks_struct* get_handle();
49 | std::vector assemble( const std::string& src, uint64_t va = 0 );
50 | };
51 |
--------------------------------------------------------------------------------
/amd64/disassembly.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 |
29 | // Furthermore, the following pieces of software have additional copyrights
30 | // licenses, and/or restrictions:
31 | //
32 | // |--------------------------------------------------------------------------|
33 | // | File name | Link for further information |
34 | // |-------------------------|------------------------------------------------|
35 | // | amd64/* | https://github.com/aquynh/capstone/ |
36 | // | | https://github.com/keystone-engine/keystone/ |
37 | // |--------------------------------------------------------------------------|
38 | //
39 | #include "disassembly.hpp"
40 |
41 | namespace capstone
42 | {
43 | csh get_handle()
44 | {
45 | // Capstone engine is not created until the first call.
46 | //
47 | static csh handle = [ ] ()
48 | {
49 | csh handle;
50 | if ( cs_open( CS_ARCH_X86, CS_MODE_64, &handle ) != CS_ERR_OK
51 | || cs_option( handle, CS_OPT_DETAIL, CS_OPT_ON ) != CS_ERR_OK )
52 | throw std::exception( "Failed to create the Capstone engine!" );
53 | return handle;
54 | }( );
55 | return handle;
56 | }
57 |
58 | std::vector disasm( const void* bytes, uint64_t address, size_t size, size_t count )
59 | {
60 | // Disasemble the instruction.
61 | //
62 | cs_insn* ins;
63 | count = cs_disasm
64 | (
65 | get_handle(),
66 | ( uint8_t* ) bytes,
67 | size ? size : -1,
68 | address,
69 | size ? 0 : count,
70 | &ins
71 | );
72 |
73 | // Convert each output into vtil::amd64 format and push it to a vector.
74 | //
75 | std::vector vec;
76 | for ( int i = 0; i < count; i++ )
77 | {
78 | vtil::amd64::instruction out;
79 | cs_insn& in = ins[ i ];
80 |
81 | // Copy cs_insn base.
82 | //
83 | out.id = in.id;
84 | out.address = in.address;
85 | out.mnemonic = in.mnemonic;
86 | out.operand_string = in.op_str;
87 | out.bytes = { in.bytes, in.bytes + in.size };
88 |
89 | // Copy cs_insn::detail.
90 | //
91 | out.regs_read = { in.detail->regs_read, in.detail->regs_read + in.detail->regs_read_count };
92 | out.regs_write = { in.detail->regs_write, in.detail->regs_write + in.detail->regs_write_count };
93 | out.groups = { in.detail->groups, in.detail->groups + in.detail->groups_count };
94 |
95 | // Copy cs_insn::detail::x86.
96 | //
97 | std::copy( std::begin( in.detail->x86.prefix ), std::end( in.detail->x86.prefix ), out.prefix );
98 | for ( int i = 0; i < 4 && in.detail->x86.opcode[ i ] != 0x0; i++ )
99 | out.opcode.push_back( in.detail->x86.opcode[ i ] );
100 | out.rex = in.detail->x86.rex;
101 | out.addr_size = in.detail->x86.addr_size;
102 | out.modrm = in.detail->x86.modrm;
103 | out.sib = in.detail->x86.sib;
104 | out.disp = in.detail->x86.disp;
105 | out.sib_index = in.detail->x86.sib_index;
106 | out.sib_scale = in.detail->x86.sib_scale;
107 | out.sib_base = in.detail->x86.sib_base;
108 | out.xop_cc = in.detail->x86.xop_cc;
109 | out.sse_cc = in.detail->x86.sse_cc;
110 | out.avx_cc = in.detail->x86.avx_cc;
111 | out.avx_sae = in.detail->x86.avx_sae;
112 | out.avx_rm = in.detail->x86.avx_rm;
113 | out.eflags = in.detail->x86.eflags;
114 | out.operands = { in.detail->x86.operands, in.detail->x86.operands + in.detail->x86.op_count };
115 | out.encoding = in.detail->x86.encoding;
116 |
117 | // Push it to up the vector.
118 | //
119 | vec.push_back( std::move( out ) );
120 | }
121 |
122 | // Free the output from Capstone and return the vector.
123 | //
124 | cs_free( ins, count );
125 | return vec;
126 | }
127 |
128 | };
--------------------------------------------------------------------------------
/amd64/disassembly.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 |
29 | // Furthermore, the following pieces of software have additional copyrights
30 | // licenses, and/or restrictions:
31 | //
32 | // |--------------------------------------------------------------------------|
33 | // | File name | Link for further information |
34 | // |-------------------------|------------------------------------------------|
35 | // | amd64/* | https://github.com/aquynh/capstone/ |
36 | // | | https://github.com/keystone-engine/keystone/ |
37 | // |--------------------------------------------------------------------------|
38 | //
39 | #pragma once
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include "..\io\formatting.hpp"
47 |
48 | namespace vtil::amd64
49 | {
50 | struct instruction
51 | {
52 | // Data copied from base of [cs_insn].
53 | //
54 | uint32_t id = 0;
55 | uint64_t address = 0;
56 | std::vector bytes;
57 | std::string mnemonic;
58 | std::string operand_string;
59 |
60 | // Data copied from [cs_insn::detail].
61 | //
62 | std::set regs_read;
63 | std::set regs_write;
64 | std::set groups;
65 |
66 | // Data copied from [cs_insn::detail::x86]
67 | //
68 | uint8_t prefix[ 4 ];
69 | std::vector opcode;
70 |
71 | uint8_t rex;
72 | uint8_t addr_size;
73 | uint8_t modrm;
74 | uint8_t sib;
75 | int64_t disp;
76 |
77 | x86_reg sib_index;
78 | int8_t sib_scale;
79 | x86_reg sib_base;
80 |
81 | x86_xop_cc xop_cc;
82 | x86_sse_cc sse_cc;
83 | x86_avx_cc avx_cc;
84 |
85 | bool avx_sae;
86 | x86_avx_rm avx_rm;
87 |
88 | union
89 | {
90 | uint64_t eflags;
91 | uint64_t fpu_flags;
92 | };
93 |
94 | std::vector operands;
95 | cs_x86_encoding encoding;
96 |
97 | // Returns human readable disassembly.
98 | //
99 | std::string to_string() const
100 | {
101 | return format::str( "%p: %s\t%s", address, mnemonic, operand_string );
102 | }
103 |
104 | // Helper to check if instruction is of type .
105 | //
106 | bool is( uint32_t idx, const std::vector& operands_t ) const
107 | {
108 | if ( id != idx ) return false;
109 | if ( operands.size() != operands_t.size() ) return false;
110 | for ( int i = 0; i < operands.size(); i++ )
111 | if ( operands[ i ].type != operands_t[ i ] )
112 | return false;
113 | return true;
114 | }
115 |
116 | // Helper to check if instruction belongs to the given group.
117 | //
118 | bool in_group( uint8_t group_searched ) const
119 | {
120 | return std::find( groups.begin(), groups.end(), group_searched ) != groups.end();
121 | }
122 | };
123 | };
124 |
125 | // Simple wrapper around Capstone disasembler.
126 | //
127 | namespace capstone
128 | {
129 | csh get_handle();
130 | std::vector disasm( const void* bytes, uint64_t address, size_t size = 0, size_t count = 1 );
131 | };
--------------------------------------------------------------------------------
/amd64/register_details.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 |
29 | // Furthermore, the following pieces of software have additional copyrights
30 | // licenses, and/or restrictions:
31 | //
32 | // |--------------------------------------------------------------------------|
33 | // | File name | Link for further information |
34 | // |-------------------------|------------------------------------------------|
35 | // | amd64/* | https://github.com/aquynh/capstone/ |
36 | // | | https://github.com/keystone-engine/keystone/ |
37 | // |--------------------------------------------------------------------------|
38 | //
39 | #include "register_details.hpp"
40 |
41 | namespace vtil::amd64
42 | {
43 | // List of all physical registers and the base registers they map to <0> at offset <1> of size <2>.
44 | //
45 | static const std::map register_mappings
46 | {
47 | /* [Instance] [Base] [Offset] [Size] */
48 | { X86_REG_RAX, { X86_REG_RAX, 0, 8 } },
49 | { X86_REG_EAX, { X86_REG_RAX, 0, 4 } },
50 | { X86_REG_AX, { X86_REG_RAX, 0, 2 } },
51 | { X86_REG_AH, { X86_REG_RAX, 1, 1 } },
52 | { X86_REG_AL, { X86_REG_RAX, 0, 1 } },
53 |
54 | { X86_REG_RBX, { X86_REG_RBX, 0, 8 } },
55 | { X86_REG_EBX, { X86_REG_RBX, 0, 4 } },
56 | { X86_REG_BX, { X86_REG_RBX, 0, 2 } },
57 | { X86_REG_BH, { X86_REG_RBX, 1, 1 } },
58 | { X86_REG_BL, { X86_REG_RBX, 0, 1 } },
59 |
60 | { X86_REG_RCX, { X86_REG_RCX, 0, 8 } },
61 | { X86_REG_ECX, { X86_REG_RCX, 0, 4 } },
62 | { X86_REG_CX, { X86_REG_RCX, 0, 2 } },
63 | { X86_REG_CH, { X86_REG_RCX, 1, 1 } },
64 | { X86_REG_CL, { X86_REG_RCX, 0, 1 } },
65 |
66 | { X86_REG_RDX, { X86_REG_RDX, 0, 8 } },
67 | { X86_REG_EDX, { X86_REG_RDX, 0, 4 } },
68 | { X86_REG_DX, { X86_REG_RDX, 0, 2 } },
69 | { X86_REG_DH, { X86_REG_RDX, 1, 1 } },
70 | { X86_REG_DL, { X86_REG_RDX, 0, 1 } },
71 |
72 | { X86_REG_RDI, { X86_REG_RDI, 0, 8 } },
73 | { X86_REG_EDI, { X86_REG_RDI, 0, 4 } },
74 | { X86_REG_DI, { X86_REG_RDI, 0, 2 } },
75 | { X86_REG_DIL, { X86_REG_RDI, 0, 1 } },
76 |
77 | { X86_REG_RSI, { X86_REG_RSI, 0, 8 } },
78 | { X86_REG_ESI, { X86_REG_RSI, 0, 4 } },
79 | { X86_REG_SI, { X86_REG_RSI, 0, 2 } },
80 | { X86_REG_SIL, { X86_REG_RSI, 0, 1 } },
81 |
82 | { X86_REG_RBP, { X86_REG_RBP, 0, 8 } },
83 | { X86_REG_EBP, { X86_REG_RBP, 0, 4 } },
84 | { X86_REG_BP, { X86_REG_RBP, 0, 2 } },
85 | { X86_REG_BPL, { X86_REG_RBP, 0, 1 } },
86 |
87 | { X86_REG_RSP, { X86_REG_RSP, 0, 8 } },
88 | { X86_REG_ESP, { X86_REG_RSP, 0, 4 } },
89 | { X86_REG_SP, { X86_REG_RSP, 0, 2 } },
90 | { X86_REG_SPL, { X86_REG_RSP, 0, 1 } },
91 |
92 | { X86_REG_R8, { X86_REG_R8, 0, 8 } },
93 | { X86_REG_R8D, { X86_REG_R8, 0, 4 } },
94 | { X86_REG_R8W, { X86_REG_R8, 0, 2 } },
95 | { X86_REG_R8B, { X86_REG_R8, 0, 1 } },
96 |
97 | { X86_REG_R9, { X86_REG_R9, 0, 8 } },
98 | { X86_REG_R9D, { X86_REG_R9, 0, 4 } },
99 | { X86_REG_R9W, { X86_REG_R9, 0, 2 } },
100 | { X86_REG_R9B, { X86_REG_R9, 0, 1 } },
101 |
102 | { X86_REG_R10, { X86_REG_R10, 0, 8 } },
103 | { X86_REG_R10D, { X86_REG_R10, 0, 4 } },
104 | { X86_REG_R10W, { X86_REG_R10, 0, 2 } },
105 | { X86_REG_R10B, { X86_REG_R10, 0, 1 } },
106 |
107 | { X86_REG_R11, { X86_REG_R11, 0, 8 } },
108 | { X86_REG_R11D, { X86_REG_R11, 0, 4 } },
109 | { X86_REG_R11W, { X86_REG_R11, 0, 2 } },
110 | { X86_REG_R11B, { X86_REG_R11, 0, 1 } },
111 |
112 | { X86_REG_R12, { X86_REG_R12, 0, 8 } },
113 | { X86_REG_R12D, { X86_REG_R12, 0, 4 } },
114 | { X86_REG_R12W, { X86_REG_R12, 0, 2 } },
115 | { X86_REG_R12B, { X86_REG_R12, 0, 1 } },
116 |
117 | { X86_REG_R13, { X86_REG_R13, 0, 8 } },
118 | { X86_REG_R13D, { X86_REG_R13, 0, 4 } },
119 | { X86_REG_R13W, { X86_REG_R13, 0, 2 } },
120 | { X86_REG_R13B, { X86_REG_R13, 0, 1 } },
121 |
122 | { X86_REG_R14, { X86_REG_R14, 0, 8 } },
123 | { X86_REG_R14D, { X86_REG_R14, 0, 4 } },
124 | { X86_REG_R14W, { X86_REG_R14, 0, 2 } },
125 | { X86_REG_R14B, { X86_REG_R14, 0, 1 } },
126 |
127 | { X86_REG_R15, { X86_REG_R15, 0, 8 } },
128 | { X86_REG_R15D, { X86_REG_R15, 0, 4 } },
129 | { X86_REG_R15W, { X86_REG_R15, 0, 2 } },
130 | { X86_REG_R15B, { X86_REG_R15, 0, 1 } },
131 |
132 | { X86_REG_EFLAGS, { X86_REG_EFLAGS, 0, 8 } },
133 | };
134 |
135 | // Gets the offset<0> and size<1> of the mapping for the given register.
136 | //
137 | register_mapping resolve_mapping( uint8_t _reg )
138 | {
139 | // Try to find the register mapping, if successful return if
140 | //
141 | auto it = register_mappings.find( ( x86_reg ) _reg );
142 | if ( it != register_mappings.end() )
143 | return it->second;
144 |
145 | // Otherwise return default mapping after making sure it's valid.
146 | //
147 | fassert( _reg != X86_REG_INVALID );
148 | return { ( x86_reg ) _reg, 0, 8 };
149 | }
150 |
151 | // Gets the base register for the given register.
152 | //
153 | x86_reg extend( uint8_t _reg )
154 | {
155 | // Try to find the register mapping,
156 | // return as is if we fail to do so.
157 | //
158 | auto it = register_mappings.find( ( x86_reg ) _reg );
159 | if ( it == register_mappings.end() )
160 | return ( x86_reg ) _reg;
161 |
162 | // Otherwise return the base register.
163 | //
164 | return it->second.base_register;
165 | }
166 |
167 | // Converts the enum into human-readable format.
168 | //
169 | std::string name( uint8_t _reg )
170 | {
171 | // Else lookup the name from capstone.
172 | //
173 | return cs_reg_name( capstone::get_handle(), ( x86_reg ) _reg );
174 | }
175 |
176 | // Remaps the given register at given specifications.
177 | //
178 | x86_reg remap( uint8_t _reg, uint8_t offset, uint8_t size )
179 | {
180 | // Extend passed register
181 | //
182 | x86_reg base_register = extend( _reg );
183 |
184 | // For each mapping described:
185 | //
186 | for ( auto& pair : register_mappings )
187 | {
188 | // If matches the specifications, return.
189 | //
190 | if ( pair.second.base_register == base_register &&
191 | pair.second.offset == offset &&
192 | pair.second.size == size )
193 | return pair.first;
194 | }
195 |
196 | // If we fail to find, and we're strictly
197 | // remapping to a full register, return as is.
198 | //
199 | fassert( offset == 0 );
200 | return base_register;
201 | }
202 | };
--------------------------------------------------------------------------------
/amd64/register_details.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 |
29 | // Furthermore, the following pieces of software have additional copyrights
30 | // licenses, and/or restrictions:
31 | //
32 | // |--------------------------------------------------------------------------|
33 | // | File name | Link for further information |
34 | // |-------------------------|------------------------------------------------|
35 | // | amd64/* | https://github.com/aquynh/capstone/ |
36 | // | | https://github.com/keystone-engine/keystone/ |
37 | // |--------------------------------------------------------------------------|
38 | //
39 | #pragma once
40 | #include
41 | #include
42 | #include
43 | #include "disassembly.hpp"
44 | #include "..\io\asserts.hpp"
45 |
46 | namespace vtil::amd64
47 | {
48 | // Structure describing how a register maps to another register.
49 | //
50 | struct register_mapping
51 | {
52 | // Base register of full size, e.g. X86_REG_RAX.
53 | //
54 | x86_reg base_register;
55 |
56 | // Offset of the current register from the base register.
57 | //
58 | uint8_t offset;
59 |
60 | // Size of the current register in bytes.
61 | //
62 | uint8_t size;
63 |
64 | inline operator std::tuple() { return { base_register, offset, size }; }
65 | };
66 |
67 | // Gets the offset<0> and size<1> of the mapping for the given register.
68 | //
69 | register_mapping resolve_mapping( uint8_t _reg );
70 |
71 | // Gets the base register for the given register.
72 | //
73 | x86_reg extend( uint8_t _reg );
74 |
75 | // Converts the enum into human-readable format.
76 | //
77 | std::string name( uint8_t _reg );
78 |
79 | // Remaps the given register at given specifications.
80 | //
81 | x86_reg remap( uint8_t _reg, uint8_t offset, uint8_t size );
82 | };
--------------------------------------------------------------------------------
/includes/vtil/amd64:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "..\..\amd64\assembler.hpp"
3 | #include "..\..\amd64\disassembly.hpp"
4 | #include "..\..\amd64\register_details.hpp"
--------------------------------------------------------------------------------
/includes/vtil/common:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
--------------------------------------------------------------------------------
/includes/vtil/io:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "..\..\io\asserts.hpp"
3 | #include "..\..\io\formatting.hpp"
4 | #include "..\..\io\logger.hpp"
--------------------------------------------------------------------------------
/includes/vtil/math:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "..\..\math\bitwise.hpp"
3 | #include "..\..\math\operators.hpp"
4 | #include "..\..\math\operable.hpp"
--------------------------------------------------------------------------------
/includes/vtil/query:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "..\..\query\range_iterator_contract.hpp"
3 | #include "..\..\query\range_iterator.hpp"
4 | #include "..\..\query\query_descriptor.hpp"
5 | #include "..\..\query\view.hpp"
6 | #include "..\..\query\recursive_view.hpp"
7 | #include "..\..\query\fixed_iterator.hpp"
--------------------------------------------------------------------------------
/includes/vtil/utility:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "..\..\util\priority_list.hpp"
3 | #include "..\..\util\critical_section.hpp"
4 | #include "..\..\util\copy_on_write.hpp"
5 | #include "..\..\util\concept.hpp"
6 | #include "..\..\util\variant.hpp"
7 | #include "..\..\util\hashable.hpp"
8 | #include "..\..\util\stack_container.hpp"
9 | #include "..\..\util\reducable.hpp"
--------------------------------------------------------------------------------
/includes/vtil/vtil:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
--------------------------------------------------------------------------------
/io/asserts.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 | #pragma once
29 | #include
30 | #include "logger.hpp"
31 |
32 | namespace vtil::assert
33 | {
34 | namespace impl { __declspec( noreturn ) __forceinline static void noreturn_helper() { __debugbreak(); } };
35 |
36 | static void or_die( bool condition, const char* file_name, const char* condition_str, uint32_t line_number )
37 | {
38 | if ( condition ) return;
39 | logger::error
40 | (
41 | "Assertion failure at %s:%d (%s)",
42 | file_name,
43 | line_number,
44 | condition_str
45 | );
46 | }
47 | };
48 |
49 | #ifdef _DEBUG
50 | #define fassert__stringify(x) #x
51 | #define fassert(x) vtil::assert::or_die( (x), __FILE__, fassert__stringify(x), __LINE__ )
52 | #else
53 | #define fassert(...)
54 | #endif
55 | #define unreachable() vtil::assert::impl::noreturn_helper()
--------------------------------------------------------------------------------
/io/formatting.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 | #pragma once
29 | #include
30 | #include
31 |
32 | // [Configuration]
33 | // Determine the way we format the instructions.
34 | //
35 | #ifndef VTIL_FMT_DEFINED
36 | #define VTIL_FMT_INS_MNM "%-8s"
37 | #define VTIL_FMT_INS_OPR "%-12s"
38 | #define VTIL_FMT_INS_MNM_S 8
39 | #define VTIL_FMT_INS_OPR_S 12
40 | #define VTIL_FMT_SUFFIX_1 'b'
41 | #define VTIL_FMT_SUFFIX_2 'w'
42 | #define VTIL_FMT_SUFFIX_4 'd'
43 | #define VTIL_FMT_SUFFIX_8 'q'
44 | #define VTIL_FMT_DEFINED
45 | #endif
46 |
47 | namespace vtil::format
48 | {
49 | // Suffixes used to indicate registers of N bytes.
50 | //
51 | static constexpr char suffix_map[] = { 0, VTIL_FMT_SUFFIX_1, VTIL_FMT_SUFFIX_2, 0, VTIL_FMT_SUFFIX_4, 0, 0, 0, VTIL_FMT_SUFFIX_8 };
52 |
53 | // Used to fix std::string usage in combination with "%s".
54 | //
55 | #ifdef __INTEL_COMPILER
56 | #pragma warning (supress:1011) // Billion dollar company yes? #2
57 | #endif
58 | template
59 | __forceinline static auto fix_parameter( T&& x )
60 | {
61 | if constexpr ( std::is_same_v, std::string> || std::is_same_v, std::wstring> )
62 | return x.data();
63 | else
64 | return std::forward( x );
65 | }
66 |
67 | // Returns formatted string according to .
68 | //
69 | template
70 | static std::string str( const char* fmt, params&&... ps )
71 | {
72 | std::string buffer;
73 | buffer.resize( snprintf( nullptr, 0, fmt, fix_parameter( std::forward( ps ) )... ) );
74 | sprintf_s( buffer.data(), buffer.size() + 1, fmt, fix_parameter( std::forward( ps ) )... );
75 | return buffer;
76 | }
77 |
78 | // Formats the integer into a signed hexadecimal.
79 | //
80 | template>, int> = 0>
81 | static std::string hex( T&& value )
82 | {
83 | if ( !std::is_signed_v> || value >= 0 )
84 | return str( "0x%llx", value );
85 | else
86 | return str( "-0x%llx", -value );
87 | }
88 |
89 | // Formats the integer into a signed hexadecimal with explicit + if positive.
90 | //
91 | static std::string offset( int64_t value )
92 | {
93 | if ( value >= 0 )
94 | return str( "+ 0x%llx", value );
95 | else
96 | return str( "- 0x%llx", -value );
97 | }
98 | };
--------------------------------------------------------------------------------
/io/logger.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 | #include "logger.hpp"
29 |
30 | #if _WIN64
31 | #define WIN32_LEAN_AND_MEAN
32 | #define NOMINMAX
33 | #include
34 | #endif
35 |
36 | namespace vtil::logger
37 | {
38 | // State of the logging engine.
39 | //
40 | critical_section log_cs;
41 | volatile bool log_disable = false;
42 | volatile int log_padding = -1;
43 | volatile int log_padding_carry = 0;
44 |
45 | namespace impl
46 | {
47 | // Internally used to change the console if possible.
48 | //
49 | void set_color( console_color color )
50 | {
51 | #if _WIN64
52 | SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), color );
53 | #endif
54 | }
55 |
56 | // Internally used to initialize the logger.
57 | //
58 | void initialize()
59 | {
60 | static bool log_init = false;
61 | if ( log_init ) return;
62 | #if _WIN64
63 | SetConsoleOutputCP( CP_UTF8 );
64 | #endif
65 | log_init = true;
66 | }
67 | };
68 | };
--------------------------------------------------------------------------------
/io/logger.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 | #pragma once
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include "formatting.hpp"
35 | #include "..\util\critical_section.hpp"
36 |
37 | namespace vtil::logger
38 | {
39 | // Console colors, only used on Windows platform.
40 | //
41 | enum console_color
42 | {
43 | CON_BRG = 15,
44 | CON_YLW = 14,
45 | CON_PRP = 13,
46 | CON_RED = 12,
47 | CON_CYN = 11,
48 | CON_GRN = 10,
49 | CON_BLU = 9,
50 | CON_DEF = 7,
51 | };
52 |
53 | // State of the logging engine.
54 | //
55 | extern critical_section log_cs;
56 | extern volatile bool log_disable;
57 | extern volatile int log_padding;
58 | extern volatile int log_padding_carry;
59 |
60 | // Padding customization for logger.
61 | //
62 | static constexpr char log_padding_c = '|';
63 | static constexpr uint32_t log_padding_step = 2;
64 |
65 | // RAII hack for incrementing the padding until routine ends.
66 | // Can be used with the argument u=0 to act as a lock guard.
67 | // - Will wait for the critical section ownership and hold it
68 | // until the scope ends.
69 | //
70 | struct scope_padding
71 | {
72 | int prev = log_padding;
73 | bool holds_lock = false;
74 | scope_padding( unsigned u ) { log_padding += u; log_cs.lock(); holds_lock = true; }
75 | void end() { if ( holds_lock ) log_cs.unlock(), holds_lock = false; log_padding = prev; }
76 | ~scope_padding() { end(); }
77 | };
78 |
79 | // RAII hack for changing verbosity of logs within the scope.
80 | // - Will wait for the critical section ownership and hold it
81 | // until the scope ends.
82 | //
83 | struct scope_verbosity
84 | {
85 | bool prev = log_disable;
86 | bool holds_lock = false;
87 | scope_verbosity( bool verbose_output ) { log_disable |= !verbose_output; log_cs.lock(); holds_lock = true; }
88 | void end() { if ( holds_lock ) log_cs.unlock(), holds_lock = false; log_disable = prev; }
89 | ~scope_verbosity() { end(); }
90 | };
91 |
92 | // Implementation details.
93 | //
94 | namespace impl
95 | {
96 | // Internally used to change the console if possible.
97 | //
98 | void set_color( console_color color );
99 |
100 | // Internally used to initialize the logger.
101 | //
102 | void initialize();
103 |
104 | // Used to mark functions noreturn.
105 | //
106 | __declspec( noreturn ) __forceinline static void noreturn_helper() { __debugbreak(); }
107 | };
108 |
109 | // Main function used when logging.
110 | //
111 | template
112 | static int log( const char* fmt, params&&... ps )
113 | {
114 | // Do not execute if logs are disabled.
115 | //
116 | if ( log_disable ) return 0;
117 |
118 | // Hold the lock for the critical section guarding ::log.
119 | //
120 | std::lock_guard g( log_cs );
121 |
122 | // Initialize logger if not done already.
123 | //
124 | impl::initialize();
125 |
126 | // Set to defualt color.
127 | //
128 | impl::set_color( CON_DEF );
129 | int out_cnt = 0;
130 |
131 | // If we should pad this output:
132 | //
133 | if ( log_padding > 0 )
134 | {
135 | // If it was not carried from previous:
136 | //
137 | if( int pad_by = log_padding - log_padding_carry )
138 | {
139 | for ( int i = 0; i < pad_by; i++ )
140 | {
141 | if ( ( i + 1 ) == pad_by )
142 | {
143 | out_cnt += printf( "%*c", log_padding_step - 1, ' ' );
144 | if ( fmt[ 0 ] == ' ' ) putchar( log_padding_c );
145 | }
146 | else
147 | {
148 | out_cnt += printf( "%*c%c", log_padding_step - 1, ' ', log_padding_c );
149 | }
150 | }
151 | }
152 |
153 | // Set or clear the carry for next.
154 | //
155 | if ( fmt[ strlen( fmt ) - 1 ] == '\n' )
156 | log_padding_carry = 0;
157 | else
158 | log_padding_carry = log_padding;
159 | }
160 |
161 | // Set to requested color and redirect to printf.
162 | //
163 | impl::set_color( color );
164 | return out_cnt + printf( fmt, format::fix_parameter( std::forward( ps ) )... );
165 | }
166 |
167 | // Prints an error message and breaks the execution.
168 | //
169 | template
170 | __declspec( noreturn ) static void error( const char* fmt, params&&... ps )
171 | {
172 | // Error will stop any execution so feel free to ignore any locks.
173 | //
174 | new ( &log_cs ) critical_section();
175 |
176 | // Print the erorr message.
177 | //
178 | log( fmt, std::forward( ps )... );
179 |
180 | // Break the program.
181 | //
182 | #ifdef _DEBUG
183 | __debugbreak();
184 | #else
185 | exit( 1 );
186 | #endif
187 | impl::noreturn_helper();
188 | }
189 | };
--------------------------------------------------------------------------------
/math/bitwise.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 | #pragma once
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include "..\util\reducable.hpp"
34 | #include "..\io\asserts.hpp"
35 |
36 | // Declare the type we will used for bit lenghts of data.
37 | // - We are using int instead of char since most operations will end up casting
38 | // this value to an integer anyway and since char does not provide us any intrinsic
39 | // safety either this only hurts us in terms of performance.
40 | //
41 | using bitcnt_t = int;
42 |
43 | namespace vtil::math
44 | {
45 | // Sizeof equivalent in bits.
46 | //
47 | template
48 | static constexpr bitcnt_t bitcnt = sizeof( T ) * 8;
49 |
50 | // Extracts the sign bit from the given value.
51 | //
52 | template, int> = 0>
53 | static constexpr bool sgn( T type ) { return bool( type >> ( bitcnt - 1 ) ); }
54 |
55 | // Implement platform-indepdenent popcnt and bit_test/set/clear/flip.
56 | //
57 | static constexpr bitcnt_t popcnt( uint64_t x )
58 | {
59 | // https://www.chessprogramming.org/Population_Count#The_PopCount_routine
60 | //
61 | x = x - ( x >> 1 ) & 0x5555555555555555;
62 | x = ( x & 0x3333333333333333 ) + ( ( x >> 2 ) & 0x3333333333333333 );
63 | x = ( x + ( x >> 4 ) ) & 0x0f0f0f0f0f0f0f0f;
64 | x = ( x * 0x0101010101010101 ) >> 56;
65 | return bitcnt_t( x );
66 | }
67 |
68 | // Generate a mask for the given variable size and offset.
69 | //
70 | static constexpr uint64_t fill( bitcnt_t bit_count, bitcnt_t bit_offset = 0 )
71 | {
72 | if ( bit_offset >= 64 ) return 0;
73 | return ( ( ~0ull ) >> ( 64 - bit_count ) ) << bit_offset;
74 | }
75 |
76 | // Fills the bits of the uint64_t type after the given offset with the sign bit.
77 | // - We accept an [uint64_t] as the sign "bit" instead of a for
78 | // the sake of a further trick we use to avoid branches.
79 | //
80 | static constexpr uint64_t fill_sign( uint64_t sign, bitcnt_t bit_offset = 0 )
81 | {
82 | // The XOR operation with 0b1 flips the sign bit, after which when we subtract
83 | // one to create 0xFF... for (1) and 0x00... for (0).
84 | // - We could have also done [s *= ~0ull], but it's slower since:
85 | // 1) XOR ~= [#μop: 1, latency: 1]
86 | // 2) SUB ~= [#μop: 1, latency: 1]
87 | // vs
88 | // 1) MUL ~= [#μop: 3, latency: 3]
89 | //
90 | return ( ( sign ^ 1 ) - 1 ) << bit_offset;
91 | }
92 |
93 | // Zero extends the given integer.
94 | //
95 | static uint64_t __zx( uint64_t value, bitcnt_t bcnt_src )
96 | {
97 | // Use simple casts where possible.
98 | //
99 | switch ( bcnt_src )
100 | {
101 | case 1: return value & 1;
102 | case 8: return *( uint8_t* ) &value;
103 | case 16: return *( uint16_t* ) &value;
104 | case 32: return *( uint32_t* ) &value;
105 | case 64: return *( uint64_t* ) &value;
106 | }
107 |
108 | // Make sure source size is non-zero.
109 | //
110 | fassert( bcnt_src != 0 );
111 |
112 | // Mask the value.
113 | //
114 | value &= fill( bcnt_src );
115 | return value;
116 | }
117 |
118 | // Sign extends the given integer.
119 | //
120 | static int64_t __sx( uint64_t value, bitcnt_t bcnt_src )
121 | {
122 | // Use simple casts where possible.
123 | //
124 | switch ( bcnt_src )
125 | {
126 | case 1: return value & 1; // Booleans cannot have sign bits by definition.
127 | case 8: return *( int8_t* ) &value;
128 | case 16: return *( int16_t* ) &value;
129 | case 32: return *( int32_t* ) &value;
130 | case 64: return *( int64_t* ) &value;
131 | }
132 |
133 | // Make sure source size is non-zero.
134 | //
135 | fassert( bcnt_src != 0 );
136 |
137 | // Extract sign bit.
138 | //
139 | uint64_t sign = ( value >> ( bcnt_src - 1 ) ) & 1;
140 |
141 | // Mask the value.
142 | //
143 | value &= fill( bcnt_src );
144 |
145 | // Extend the sign bit.
146 | // - Small trick is used here to avoid branches.
147 | //
148 | sign = ( ( sign ^ 1 ) - 1 ) << bcnt_src;
149 | return value | sign;
150 | }
151 |
152 | // Return value from bit-vector lookup where the result can be either unknown or constant 0/1.
153 | //
154 | enum class bit_state : int8_t
155 | {
156 | zero = -1,
157 | unknown = 0,
158 | one = +1,
159 | };
160 |
161 | // Bit-vector holding 0 to 64 bits of value with optional unknowns.
162 | //
163 | class bit_vector : public reducable
164 | {
165 | // Value of the known bits, mask of it can be found by [::known_mask()]
166 | // - Guaranteed to hold 0 for unknown bits.
167 | //
168 | uint64_t known_bits = 0;
169 |
170 | // Mask for the bit that we do not know.
171 | // - Guaranteed to hold 0 for known bits and for all bits above bit_count.
172 | //
173 | uint64_t unknown_bits = 0;
174 |
175 | // Number of bits this vector contains.
176 | //
177 | bitcnt_t bit_count = 0;
178 |
179 | public:
180 | // Default constructor, will result in invalid bit-vector.
181 | //
182 | bit_vector() = default;
183 |
184 | // Constructs a bit-vector where all bits are set according to the state.
185 | // - Declared explicit to avoid construction from integers.
186 | //
187 | explicit bit_vector( bitcnt_t bit_count ) :
188 | bit_count( bit_count ), unknown_bits( fill( bit_count ) ), known_bits( 0 ) {}
189 |
190 | // Constructs a bit-vector where all bits are known.
191 | //
192 | bit_vector( uint64_t value, bitcnt_t bit_count ) :
193 | bit_count( bit_count ), unknown_bits( 0 ), known_bits( value & fill( bit_count ) ) {}
194 |
195 | // Constructs a bit-vector where bits are partially known.
196 | //
197 | bit_vector( uint64_t known_bits, uint64_t unknown_bits, bitcnt_t bit_count ) :
198 | bit_count( bit_count ), unknown_bits( unknown_bits & fill( bit_count ) ), known_bits( known_bits & ~( unknown_bits & fill( bit_count ) ) ) {}
199 |
200 | // Some helpers to access the internal state.
201 | //
202 | inline uint64_t value_mask() const { return fill( bit_count ); }
203 | inline uint64_t unknown_mask() const { return unknown_bits; }
204 | inline uint64_t known_mask() const { return fill( bit_count ) & ~unknown_bits; }
205 | inline uint64_t known_one() const { return known_bits; }
206 | inline uint64_t known_zero() const { return ~( unknown_bits | known_bits ); }
207 | inline bool all_zero() const { return unknown_bits == 0 && !known_bits; }
208 | inline bool all_one() const { return unknown_bits == 0 && ( known_bits == fill( bit_count ) ); }
209 | inline bool is_valid() const { return bit_count != 0; }
210 | inline bool is_known() const { return bit_count && unknown_bits == 0; }
211 | inline bool is_unknown() const { return !bit_count || unknown_bits != 0; }
212 | inline bitcnt_t size() const { return bit_count; }
213 |
214 | // Gets the value represented, and nullopt if vector has unknown bits.
215 | //
216 | template
217 | std::optional get() const
218 | {
219 | if ( is_known() )
220 | {
221 | if constexpr ( std::is_signed_v )
222 | return ( type ) __sx( known_bits, bit_count );
223 | else
224 | return ( type ) __zx( known_bits, bit_count );
225 | }
226 | return std::nullopt;
227 | }
228 | template>
229 | inline std::optional get() const { return get(); }
230 |
231 | // Extends or shrinks the the vector.
232 | //
233 | bit_vector& resize( bitcnt_t new_size, bool signed_cast = false )
234 | {
235 | fassert( 0 < new_size && new_size <= 64 );
236 |
237 | if( signed_cast && new_size > bit_count )
238 | {
239 | bit_state sign_bit = at( bit_count - 1 );
240 | bool sign_bit_unk = at( bit_count - 1 ) == bit_state::unknown;
241 |
242 | if ( sign_bit == bit_state::unknown )
243 | unknown_bits |= fill( 64, bit_count );
244 | else if ( sign_bit == bit_state::one )
245 | known_bits |= fill( 64, bit_count );
246 | }
247 |
248 | bit_count = new_size;
249 | known_bits &= fill( new_size );
250 | unknown_bits &= fill( new_size );
251 | return *this;
252 | }
253 |
254 | // Gets the state of the bit at the index given.
255 | //
256 | bit_state at( bitcnt_t n ) const
257 | {
258 | if ( unknown_bits & ( 1ull << n ) ) return bit_state::unknown;
259 | return bit_state( ( ( ( known_bits >> n ) & 1 ) << 1 ) - 1 );
260 | }
261 | inline bit_state operator[]( bitcnt_t n ) const { return at( n ); }
262 |
263 | // Conversion to human-readable format.
264 | //
265 | std::string to_string() const
266 | {
267 | std::string out;
268 | for ( int n = bit_count - 1; n >= 0; n-- )
269 | {
270 | uint64_t mask = 1ull << n;
271 | out += ( unknown_bits & mask ) ? '?' : ( known_bits & mask ) ? '1' : '0';
272 | }
273 | return out;
274 | }
275 |
276 | // Declare reduction.
277 | // - Note: Relative comparison operators should not be used for actual comparison
278 | // but are there for the use of sorted containers.
279 | //
280 | auto reduce() { return std::tie( bit_count, known_bits, unknown_bits ); }
281 | };
282 | };
--------------------------------------------------------------------------------
/math/operable.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 | #pragma once
29 | #include
30 | #include
31 | #include
32 | #include "operators.hpp"
33 | #include "bitwise.hpp"
34 |
35 | // Operables provide a very easy way to generate lazy math operators for all
36 | // [Class x Integer], [Integer x Class], [Class x Class] posibilities as
37 | // long as the base class provides 2 constructors by contract.
38 | //
39 | // template, int> = 0>
40 | // - base_class( T value )
41 | // => operable( value )
42 | //
43 | // - base_class( operator_desc, const base_class& ) // For unary operators (Optionaly T&&)
44 | // - base_class( const base_class&, operator_desc, const base_class& ) // For binary operators (Optionaly T&&)
45 | // => operable(), operable::bit_count must be set at constructor.
46 | //
47 | //
48 | namespace vtil::math
49 | {
50 | // Declare base operable type.
51 | //
52 | template
53 | struct operable
54 | {
55 | // Value of the operand.
56 | //
57 | math::bit_vector value = {};
58 |
59 | // Default constructor and the constructor for constant values.
60 | //
61 | operable() = default;
62 | template, int> = 0>
63 | operable( T value, bitcnt_t bit_count = sizeof( T ) * 8 ) : value( uint64_t( value ), bit_count ) {}
64 |
65 | // Gets the value represented, and nullopt if value has unknown bits.
66 | //
67 | template
68 | std::optional get() const { return value.get(); }
69 | template>
70 | inline std::optional get() const { return value.get(); }
71 |
72 | // Redirect certain helpers to bit_vector.
73 | //
74 | inline bitcnt_t size() const { return value.size(); }
75 | inline uint64_t known_mask() const { return value.known_mask(); }
76 | inline uint64_t unknown_mask() const { return value.unknown_mask(); }
77 | inline uint64_t known_one() const { return value.known_one(); }
78 | inline uint64_t known_zero() const { return value.known_zero(); }
79 | inline bool is_constant() const { return value.is_known(); }
80 |
81 | // Resizes the constant, must be overriden by the base type to handle unknowns.
82 | //
83 | void resize( bitcnt_t new_size, bool sign_extend = false )
84 | {
85 | fassert( value.is_known() );
86 | value.resize( new_size, sign_extend );
87 | }
88 | };
89 |
90 | // Whether the type is a operable> instance or not.
91 | //
92 | template
93 | static constexpr bool is_custom_operable_v = std::is_base_of_v, T>;
94 |
95 | // Whether the type is operable in combination with an operable> instance or not.
96 | //
97 | template
98 | static constexpr bool is_operable_v = std::is_integral_v || is_custom_operable_v;
99 |
100 | // Whether given types are cross-operable or not.
101 | //
102 | template
103 | static constexpr bool is_xoperable()
104 | {
105 | // If T1 is a custom operable, T2 needs to be either an integral type or same type as T1.
106 | //
107 | if constexpr ( is_custom_operable_v )
108 | return std::is_integral_v || std::is_same_v;
109 |
110 | // If only T2 is a custom operable, T1 needs to be an integral type.
111 | //
112 | else if constexpr ( is_custom_operable_v )
113 | return std::is_integral_v;
114 | return false;
115 | }
116 |
117 | // Can be overriden externally to allow aliases.
118 | //
119 | template
120 | struct resolve_alias { using type = typename T1; };
121 |
122 | // Removes all qualifiers and resolves the base if aliased.
123 | //
124 | template
125 | using strip_operable_t = typename resolve_alias>::type;
126 |
127 | // Returns the result of the cross-operation between two types, void if not cross-operable.
128 | //
129 | template,
131 | typename base_type_2 = strip_operable_t,
132 | std::enable_if_t(), int> = 0
133 | >
134 | struct xop_result
135 | {
136 | using type = std::conditional_t<
137 | is_custom_operable_v,
138 | base_type_1,
139 | base_type_2
140 | >;
141 | };
142 | };
143 |
144 | // Operations with operable types
145 | //
146 | #define DEFINE_OPERATION(...) \
147 | template::type> \
148 | static result_t __VA_ARGS__
149 |
150 | #undef __max // Seriously stdlib?
151 | #undef __min
152 |
153 | DEFINE_OPERATION( operator~( T1&& a ) { return { vtil::math::operator_id::bitwise_not, std::forward( a ) }; } );
154 | DEFINE_OPERATION( operator&( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::bitwise_and, std::forward( b ) }; } );
155 | DEFINE_OPERATION( operator|( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::bitwise_or, std::forward( b ) }; } );
156 | DEFINE_OPERATION( operator^( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::bitwise_xor, std::forward( b ) }; } );
157 | DEFINE_OPERATION( operator>>( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::shift_right, std::forward( b ) }; } );
158 | DEFINE_OPERATION( operator<<( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::shift_left, std::forward( b ) }; } );
159 | DEFINE_OPERATION( __rotr( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::rotate_right, std::forward( b ) }; } );
160 | DEFINE_OPERATION( __rotl( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::rotate_left, std::forward( b ) }; } );
161 | DEFINE_OPERATION( operator-( T1&& a ) { return { vtil::math::operator_id::negate, std::forward( a ) }; } );
162 | DEFINE_OPERATION( operator+( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::add, std::forward( b ) }; } );
163 | DEFINE_OPERATION( operator-( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::subtract, std::forward( b ) }; } );
164 | DEFINE_OPERATION( imulhi( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::multiply_high, std::forward( b ) }; } );
165 | DEFINE_OPERATION( operator*( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::multiply, std::forward( b ) }; } );
166 | DEFINE_OPERATION( operator/( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::divide, std::forward( b ) }; } );
167 | DEFINE_OPERATION( operator%( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::remainder, std::forward( b ) }; } );
168 | DEFINE_OPERATION( umulhi( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::umultiply_high, std::forward( b ) }; } );
169 | DEFINE_OPERATION( umul( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::umultiply, std::forward( b ) }; } );
170 | DEFINE_OPERATION( udiv( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::udivide, std::forward( b ) }; } );
171 | DEFINE_OPERATION( urem( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::uremainder, std::forward( b ) }; } );
172 | DEFINE_OPERATION( __ucast( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::ucast, std::forward( b ) }; } );
173 | DEFINE_OPERATION( __cast( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::cast, std::forward( b ) }; } );
174 | DEFINE_OPERATION( __popcnt( T1&& a ) { return { vtil::math::operator_id::popcnt, std::forward( a ) }; } );
175 | DEFINE_OPERATION( __bt( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::bit_test, std::forward( b ) }; } );
176 | DEFINE_OPERATION( __mask( T1&& a ) { return { vtil::math::operator_id::mask, std::forward( a ) }; } );
177 | DEFINE_OPERATION( __bcnt( T1&& a ) { return { vtil::math::operator_id::bit_count, std::forward( a ) }; } );
178 | DEFINE_OPERATION( __if( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::value_if, std::forward( b ) }; } );
179 | DEFINE_OPERATION( __max( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::max_value, std::forward( b ) }; } );
180 | DEFINE_OPERATION( __min( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::min_value, std::forward( b ) }; } );
181 | DEFINE_OPERATION( __umax( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::umax_value, std::forward( b ) }; } );
182 | DEFINE_OPERATION( __umin( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::umin_value, std::forward( b ) }; } );
183 | DEFINE_OPERATION( operator>( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::greater, std::forward( b ) }; } );
184 | DEFINE_OPERATION( operator>=( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::greater_eq, std::forward( b ) }; } );
185 | DEFINE_OPERATION( operator==( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::equal, std::forward( b ) }; } );
186 | DEFINE_OPERATION( operator!=( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::not_equal, std::forward( b ) }; } );
187 | DEFINE_OPERATION( operator<=( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::less_eq, std::forward( b ) }; } );
188 | DEFINE_OPERATION( operator<( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::less, std::forward( b ) }; } );
189 | DEFINE_OPERATION( __ugreat( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::ugreater, std::forward( b ) }; } );
190 | DEFINE_OPERATION( __ugreat_eq( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::ugreater_eq, std::forward( b ) }; } );
191 | DEFINE_OPERATION( __uless_eq( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::uless_eq, std::forward( b ) }; } );
192 | DEFINE_OPERATION( __uless( T1&& a, T2&& b ) { return { std::forward( a ), vtil::math::operator_id::uless, std::forward( b ) }; } );
193 | #undef DEFINE_OPERATION
--------------------------------------------------------------------------------
/math/operators.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 | #pragma once
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include "bitwise.hpp"
35 |
36 | namespace vtil::math
37 | {
38 | enum class operator_id : uint8_t
39 | {
40 | invalid, // =
41 |
42 | // ------------------ Bitwise Operators ------------------ //
43 |
44 | // Bitwise modifiers:
45 | //
46 | bitwise_not, // ~RHS
47 |
48 | // Basic bitwise operations:
49 | //
50 | bitwise_and, // LHS&(RHS&...)
51 | bitwise_or, // LHS|(RHS|...)
52 | bitwise_xor, // LHS^(RHS^...)
53 |
54 | // Distributing bitwise operations:
55 | //
56 | shift_right, // LHS>>(RHS+...)
57 | shift_left, // LHS<<(RHS+...)
58 | rotate_right, // LHS>](RHS+...)
59 | rotate_left, // LHS[<(RHS+...)
60 |
61 | // ---------------- Arithmetic Operators ----------------- //
62 |
63 | // Arithmetic modifiers:
64 | //
65 | negate, // -RHS
66 |
67 | // Basic arithmetic operations:
68 | //
69 | add, // LHS+(RHS+...)
70 | subtract, // LHS-(RHS+...)
71 |
72 | // Distributing arithmetic operations:
73 | //
74 | multiply_high, // HI(LHS*RHS)
75 | multiply, // LHS*(RHS*...)
76 | divide, // LHS/(RHS*...)
77 | remainder, // LHS%RHS
78 |
79 | umultiply_high, // < Unsigned variants of above >
80 | umultiply, //
81 | udivide, //
82 | uremainder, //
83 |
84 | // ----------------- Special Operators ----------------- //
85 | ucast, // uintRHS_t(LHS, RHS)
86 | cast, // intRHS_t(LHS, RHS)
87 | popcnt, // POPCNT(RHS)
88 | bit_test, // [LHS>>RHS]&1
89 | mask, // RHS.mask()
90 | bit_count, // RHS.bitcount()
91 | value_if, // LHS&1 ? RHS : 0
92 |
93 | max_value, // LHS>=RHS ? LHS : RHS
94 | min_value, // LHS<=RHS ? LHS : RHS
95 |
96 | umax_value, // < Unsigned variants of above >
97 | umin_value, //
98 |
99 | greater, // LHS > RHS
100 | greater_eq, // LHS >= RHS
101 | equal, // LHS == RHS
102 | not_equal, // LHS != RHS
103 | less_eq, // LHS <= RHS
104 | less, // LHS < RHS
105 |
106 | ugreater, // < Unsigned variants of above > [Note: equal and not_equal are always unsigned.]
107 | ugreater_eq, //
108 | uless_eq, //
109 | uless, //
110 | max,
111 | };
112 |
113 | // Basic properties of each operator.
114 | //
115 | struct operator_desc
116 | {
117 | // >0 if bitwise operations are preferred as operands, <0 if arithmetic, ==0 if neutral.
118 | //
119 | int hint_bitwise;
120 |
121 | // Whether it expects signed operands or not.
122 | //
123 | bool is_signed;
124 |
125 | // Number of operands it takes. Either 1 or 2.
126 | //
127 | size_t operand_count;
128 |
129 | // Whether the operation is commutative or not.
130 | //
131 | bool is_commutative;
132 |
133 | // Symbol of the operation.
134 | //
135 | const char* symbol;
136 |
137 | // Name of the function associated with the operation.
138 | //
139 | const char* function_name;
140 |
141 | // Creates a string representation based on the operands passed.
142 | //
143 | inline std::string to_string( const std::string& lhs, const std::string& rhs ) const
144 | {
145 | // If unary function:
146 | //
147 | if ( operand_count == 1 )
148 | {
149 | // If it has a symbol, use it, else return in function format.
150 | //
151 | if ( symbol ) return symbol + rhs;
152 | else return format::str( "%s(%s)", function_name, rhs );
153 | }
154 | // If binary function:
155 | //
156 | else if ( operand_count == 2 )
157 | {
158 | // If it has a symbol, use it, else return in function format.
159 | //
160 | if ( symbol ) return format::str( "(%s%s%s)", lhs, symbol, rhs );
161 | else return format::str( "%s(%s, %s)", function_name, lhs, rhs );
162 | }
163 | unreachable();
164 | }
165 | };
166 | static constexpr operator_desc descriptors[] =
167 | {
168 | // Skipping ::invalid.
169 | {},
170 |
171 | /* [Bitwise] [Signed] [#Op] [Commutative] [Symbol] [Name] */
172 | { +1, false, 1, false, "~", "not" },
173 | { +1, false, 2, true, "&", "and" },
174 | { +1, false, 2, true, "|", "or" },
175 | { +1, false, 2, true, "^", "xor" },
176 | { +1, false, 2, false, ">>", "shr" },
177 | { +1, false, 2, false, "<<", "shl" },
178 | { +1, false, 2, false, ">]", "rotr" },
179 | { +1, false, 2, false, "[<", "rotl" },
180 | { -1, true, 1, false, "-", "neg" },
181 | { -1, true, 2, true, "+", "add" },
182 | { -1, true, 2, false, "-", "sub" },
183 | { -1, true, 2, true, "h*", "mulhi" },
184 | { -1, true, 2, true, "*", "mul" },
185 | { -1, true, 2, false, "/", "div" },
186 | { -1, true, 2, false, "%", "rem" },
187 | { -1, false, 2, true, "uh*", "umulhi" },
188 | { -1, false, 2, true, "u*", "umul" },
189 | { -1, false, 2, false, "u/", "udiv" },
190 | { -1, false, 2, false, "u%", "urem" },
191 | { 0, false, 2, false, nullptr, "__ucast" },
192 | { -1, true, 2, false, nullptr, "__cast" },
193 | { +1, false, 1, false, nullptr, "__popcnt" },
194 | { +1, false, 2, false, nullptr, "__bt" },
195 | { +1, false, 1, false, nullptr, "__mask" },
196 | { 0, false, 1, false, nullptr, "__bcnt" },
197 | { 0, false, 2, false, "?", "if" },
198 | { 0, false, 2, false, nullptr, "max" },
199 | { 0, false, 2, false, nullptr, "min" },
200 | { 0, true, 2, false, nullptr, "umax" },
201 | { 0, true, 2, false, nullptr, "umin" },
202 | { -1, true, 2, false, ">", "greater" },
203 | { -1, true, 2, false, ">=", "greater_eq" },
204 | { 0, false, 2, false, "==", "equal" },
205 | { 0, false, 2, false, "!=", "not_equal" },
206 | { -1, true, 2, false, "<=", "less_eq" },
207 | { -1, true, 2, false, "<", "less" },
208 | { 0, false, 2, false, "u>", "ugreater" },
209 | { 0, false, 2, false, "u>=", "ugreater_eq" },
210 | { 0, false, 2, false, "u<=", "uless_eq" },
211 | { 0, false, 2, false, "u<", "uless" },
212 | };
213 | static_assert( std::size( descriptors ) == size_t( operator_id::max ), "Operator descriptor table is invalid." );
214 | inline static const operator_desc* descriptor_of( operator_id id ) { return ( operator_id::invalid < id && id < operator_id::max ) ? &descriptors[ ( size_t ) id ] : nullptr; }
215 |
216 | // Operators that return bit-indices, always use the following size.
217 | //
218 | static constexpr bitcnt_t bit_index_size = 8;
219 |
220 | // Before operators return their result, the result size is always
221 | // rounded up to either 1, 8, 16, 32 or 64 (where available).
222 | //
223 | inline static constexpr bitcnt_t round_bit_count( bitcnt_t n )
224 | {
225 | if ( n > 32 ) return 64;
226 | else if ( n > 16 ) return 32;
227 | else if ( n > 8 ) return 16;
228 | else if ( n > 1 ) return 8;
229 | else return 1;
230 | }
231 |
232 | // Calculates the size of the result after after the application of the operator [id] on the operands.
233 | //
234 | bitcnt_t result_size( operator_id id, bitcnt_t bcnt_lhs, bitcnt_t bcnt_rhs );
235 |
236 | // Applies the specified operator [id] on left hand side [lhs] and right hand side [rhs]
237 | // and returns the output as a masked unsigned 64-bit integer <0> and the final size <1>.
238 | //
239 | std::pair evaluate( operator_id id, bitcnt_t bcnt_lhs, uint64_t lhs, bitcnt_t bcnt_rhs, uint64_t rhs );
240 |
241 | // Applies the specified operator [op] on left hand side [lhs] and right hand side [rhs] wher
242 | // input and output values are expressed in the format of bit-vectors with optional unknowns,
243 | // and no size constraints.
244 | //
245 | bit_vector evaluate_partial( operator_id op, const bit_vector& lhs, const bit_vector& rhs );
246 | };
--------------------------------------------------------------------------------
/query/fixed_iterator.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 | #pragma once
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include "..\io\asserts.hpp"
34 | #include "range_iterator.hpp"
35 |
36 | // Fixed iterators are used to create simple iterators that are valid range iterators
37 | // from a structure that is not based on a container, but still benefits from a common
38 | // enumeration method and vtil::query system.
39 | //
40 | namespace vtil::query
41 | {
42 | // Implement a fixed iterator end that redirects comparison to .is_end(),
43 | // in a similar way to how nullptr and nullopt works
44 | //
45 | struct fixed_iterator_end_t
46 | {
47 | struct _tag {};
48 | constexpr explicit fixed_iterator_end_t( _tag ) {}
49 | };
50 | inline constexpr fixed_iterator_end_t fixed_iterator_end{ fixed_iterator_end_t::_tag{} };
51 |
52 | // If vector entries are not pointers, they will be used to generate
53 | // fake const_iterators mapping to each entry.
54 | //
55 | template
56 | struct fixed_iterator
57 | {
58 | // Export the required traits of range iterators.
59 | //
60 | using container_type = _container_type;
61 | using value_type = _value_type;
62 | using iterator_type = const value_type*;
63 | using recurse_function = std::vector(*)( container_type* self, bool forward );
64 |
65 | // Export the required traits of an standard iterator.
66 | //
67 | using iterator_category = std::random_access_iterator_tag;
68 | using difference_type = size_t;
69 | using pointer = const value_type*;
70 | using reference = const value_type&;
71 |
72 | // Fixed iterator consists of a container, a vector that
73 | // holds the values to be iterated, and a optional recursion
74 | // helper that describes what to do on a recursion attempt.
75 | //
76 | container_type* container = nullptr;
77 | std::vector fixed_range = {};
78 | recurse_function recurse_helper = nullptr;
79 | size_t at = 0;
80 |
81 | // Implement basic requirements of range iterators and data access.
82 | //
83 | reference operator*() const { return fixed_range[ at ]; }
84 | pointer operator->() const { return &fixed_range[ at ]; }
85 | bool is_end() const { return at == fixed_range.size(); }
86 | bool is_begin() const { return at == 0; }
87 | bool is_valid() const { return container && at < fixed_range.size(); }
88 |
89 | // Redirect to helper where relevant, if not return empty vector.
90 | //
91 | std::vector recurse( bool forward ) const
92 | {
93 | if ( !container || !recurse_helper )
94 | return {};
95 | return recurse_helper( container, forward );
96 | }
97 | };
98 |
99 | // If vector entries are pointers, they will be used to generate
100 | // fake iterators mapping to the address pointed by each entry instead.
101 | //
102 | template
103 | struct fixed_iterator<_container_type, _value_type*>
104 | {
105 | // Export the required traits of range iterators.
106 | //
107 | using container_type = _container_type;
108 | using value_type = _value_type;
109 | using iterator_type = value_type*;
110 | using recurse_function = std::vector(*)(container_type* self, bool forward);
111 |
112 | // Export the required traits of an standard iterator.
113 | //
114 | using iterator_category = std::random_access_iterator_tag;
115 | using difference_type = size_t;
116 | using pointer = value_type*;
117 | using reference = value_type&;
118 |
119 | // Fixed iterator consists of a container, a vector that
120 | // holds the values to be iterated, and a optional recursion
121 | // helper that describes what to do on a recursion attempt.
122 | //
123 | container_type* container = nullptr;
124 | std::vector fixed_range = {};
125 | recurse_function recurse_helper = nullptr;
126 | size_t at = 0;
127 |
128 | // Implement basic requirements of range iterators and data access.
129 | //
130 | reference operator*() const { return *fixed_range[ at ]; }
131 | value_type operator->() const { return fixed_range[ at ]; }
132 | bool is_end() const { return at == fixed_range.size(); }
133 | bool is_begin() const { return at == 0; }
134 | bool is_valid() const { return container && at < fixed_range.size(); }
135 |
136 | // Redirect to helper where relevant, if not return empty vector.
137 | //
138 | std::vector recurse( bool forward ) const
139 | {
140 | if ( !container || !recurse_helper )
141 | return {};
142 | return recurse_helper( container, forward );
143 | }
144 | };
145 | };
146 |
147 | // Implement random-access iterator properties, by redirecting to size_t ::at.
148 | //
149 | template
150 | static auto& operator+=( vtil::query::fixed_iterator& a, size_t i ) { a.at += i; return a; }
151 | template
152 | static auto& operator++( vtil::query::fixed_iterator& a ) { a.at++; return a; }
153 | template
154 | static auto& operator--( vtil::query::fixed_iterator& a ) { a.at--; return a; }
155 | template
156 | static size_t operator-( const vtil::query::fixed_iterator& a,
157 | const vtil::query::fixed_iterator& b )
158 | {
159 | fassert( a.container == b.container && a.fixed_range == b.fixed_range );
160 | return a.at - b.at;
161 | }
162 |
163 | // Implement equality comparison between same type and the end type.
164 | //
165 | template
166 | static bool operator==( const vtil::query::fixed_iterator& a, compared_type&& b )
167 | {
168 | // Assert sanity of the comparison.
169 | //
170 | constexpr bool compare_w_fixed_end = std::is_same_v, vtil::query::fixed_iterator_end_t>;
171 | constexpr bool compare_w_iterator = std::is_same_v, vtil::query::fixed_iterator>;
172 | static_assert( compare_w_fixed_end || compare_w_iterator, "Invalid fixed type comparison." );
173 |
174 | // If comparing against fixed_iteartor_end, just check if a is at the end.
175 | //
176 | if constexpr ( compare_w_fixed_end )
177 | return a.is_end();
178 |
179 | // Othewrise compare every property.
180 | //
181 | if constexpr( compare_w_iterator )
182 | return a.container == b.container && a.fixed_range == b.fixed_range && a.at == b.at;
183 |
184 | }
185 | template
186 | static bool operator!=( const vtil::query::fixed_iterator& a, compared_type&& b ) { return !operator==( a, std::forward( b ) ); }
--------------------------------------------------------------------------------
/query/query_descriptor.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 | #pragma once
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include "range_iterator.hpp"
34 |
35 | namespace vtil::query
36 | {
37 | // Query descriptor is a structure describing the iteration state of any
38 | // query object in dependent to the currently projected type.
39 | //
40 | template
41 | struct query_desc
42 | {
43 | using iterator_type = _iterator_type;
44 | using reference_type = decltype( *std::declval() );
45 |
46 | // Current range iterator.
47 | //
48 | iterator_type iterator = {};
49 |
50 | // Direction of iteration:
51 | // => +1 for forward
52 | // => -1 for backwar
53 | //
54 | int8_t direction = 0;
55 |
56 | // Iteration function let's us define a generic iteration logic.
57 | //
58 | // Returns:
59 | // - 1 if there's a valid result
60 | // - 0 if reached end of the stream
61 | // - -1 if terminated due to until(...)
62 | //
63 | using fn_controller = std::function;
64 | fn_controller controller = [ ] ( query_desc&, iterator_type ) { return 1; };
65 |
66 | // Queries can be simply constructed from an iterator and an
67 | // optional direction value, where it defaults to forward iteration
68 | // if not .end(), backwards otherwise.
69 | //
70 | query_desc() = default;
71 | inline query_desc( iterator_type it, int8_t dir = 0 ) : iterator( it )
72 | {
73 | if ( it.is_end() && !it.is_begin() )
74 | direction = dir != 0 ? dir : -1;
75 | else
76 | direction = dir != 0 ? dir : +1;
77 | }
78 |
79 | // Wraps ::recurse(...) of range iterators, returning query descriptors.
80 | //
81 | std::vector recurse() const
82 | {
83 | // Return an empty list if direction is invalid.
84 | //
85 | if ( direction == 0 ) return {};
86 |
87 | // Get the list of possible iterators we could continue from.
88 | //
89 | std::vector iterators = iterator.recurse( direction == +1 );
90 |
91 | // Convert into query descriptors.
92 | //
93 | std::vector query_descriptors;
94 | for ( iterator_type& it : iterators )
95 | {
96 | // Create a default descriptor with the iterator and the direction,
97 | // afterwards propagate the iteration logic.
98 | //
99 | query_desc qd = { it, direction };
100 | qd.controller = controller;
101 | query_descriptors.push_back( qd );
102 | }
103 | return query_descriptors;
104 | }
105 |
106 | // Invalidates current query.
107 | //
108 | inline void stop() { iterator = prev(); direction = 0; }
109 |
110 | // Value that next() processed previously.
111 | //
112 | inline iterator_type prev() const { return direction != +1 ? iterator : ( iterator.is_begin() ? iterator_type{} : std::prev( iterator ) ); }
113 |
114 | // Value that next() will process next.
115 | //
116 | inline iterator_type next() const { return direction != -1 ? iterator : ( iterator.is_begin() ? iterator_type{} : std::prev( iterator ) ); }
117 |
118 | // Reverses the current query direction
119 | //
120 | void reverse()
121 | {
122 | // We have to fix the iterators since
123 | // .end() is valid for [-1] but not [+1]
124 | // and .begin() is valid for [+1] but not [-1].
125 | //
126 | if ( direction == -1 )
127 | {
128 | if ( !iterator.is_begin() ) --iterator;
129 | direction = +1;
130 | }
131 | else if ( direction == +1 )
132 | {
133 | if ( !iterator.is_end() ) ++iterator;
134 | direction = -1;
135 | }
136 | }
137 |
138 | // Forwards the iterator in the specified direction [n] times.
139 | //
140 | int forward( int n = 1 )
141 | {
142 | // Until we exhaust the item counter:
143 | //
144 | while ( n > 0 )
145 | {
146 | // If direction is backwards:
147 | //
148 | if ( direction == -1 )
149 | {
150 | // If we've reached .begin(), break.
151 | //
152 | if ( iterator.is_begin() )
153 | break;
154 |
155 | // Point the iterator at the current item.
156 | //
157 | --iterator;
158 |
159 | // If invalid, break.
160 | //
161 | if ( !iterator.is_valid() )
162 | break;
163 | }
164 | // If direction is forwards:
165 | //
166 | else if ( direction == +1 )
167 | {
168 | // If we've reached .end(), break.
169 | //
170 | if ( iterator.is_end() )
171 | break;
172 | }
173 | // If no direction specified, break.
174 | //
175 | else
176 | {
177 | break;
178 | }
179 |
180 | // Invoke the iteration logic.
181 | //
182 | int res = controller( *this, iterator );
183 |
184 | // If direction was forward, increment the iterator now.
185 | //
186 | if ( direction == +1 )
187 | ++iterator;
188 |
189 | // If a breaking condition was satisfied, report so.
190 | //
191 | if ( res == -1 )
192 | return -1;
193 |
194 | // If filters were passed and we've exhausted the
195 | // item counter, report success.
196 | //
197 | if ( res == 1 && --n <= 0 )
198 | return 1;
199 | }
200 |
201 | // Report end-of-stream.
202 | //
203 | return 0;
204 | }
205 | };
206 | };
--------------------------------------------------------------------------------
/query/range_iterator.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 | #pragma once
29 | #include
30 | #include
31 | #include "range_iterator_contract.hpp"
32 |
33 | // Range iterators are cross-container iterators used by the VTIL queries in order to make the
34 | // iteration of trees, in our specific use case the basic blocks, easier.
35 | //
36 | namespace vtil::query
37 | {
38 | // Basic range iterators provide a simple range iterator implementation for default STL container and pretty much
39 | // any other container adhereing to their standards to be used with VTIL queries.
40 | //
41 | template, typename _container_type::const_iterator, typename _container_type::iterator>>
43 | struct basic_range_iterator : _iterator_type
44 | {
45 | using container_type = _container_type;
46 | using iterator_type = _iterator_type;
47 |
48 | // Reference to the container.
49 | //
50 | container_type* container = nullptr;
51 |
52 | // Default constructor and the container-bound constructor.
53 | //
54 | basic_range_iterator() = default;
55 | basic_range_iterator( container_type* container, iterator_type i ) : iterator_type( i ), container( container ) {}
56 | template basic_range_iterator( const basic_range_iterator& o ) : container( o.container ), iterator_type( Y( o ) ) {}
57 |
58 | // Override equality operators to check container first.
59 | //
60 | bool operator==( const basic_range_iterator& o ) const { return container == o.container && iterator_type::operator==( o ); }
61 | bool operator!=( const basic_range_iterator& o ) const { return container != o.container || iterator_type::operator!=( o ); }
62 |
63 | // Simple position/validity checks.
64 | //
65 | bool is_end() const { return !container || iterator_type::operator==( ( iterator_type ) container->end() ); }
66 | bool is_begin() const { return !container || iterator_type::operator==( ( iterator_type ) container->begin() ); }
67 | bool is_valid() const { return !is_begin() || !is_end(); }
68 |
69 | // No default implementation for recursion since STL has no default tree-based container.
70 | //
71 | std::vector recurse( bool forward ) const { return {}; }
72 | };
73 |
74 | // Makes range iterator from any container and iterator combination based on basic_range_iterator.
75 | //
76 | template
77 | static auto bind( container_type& container, iterator_type iterator ) { return basic_range_iterator{ &container, iterator }; }
78 |
79 | // Make sure contract is being abided.
80 | //
81 | static_assert
82 | (
83 | is_range_iterator_v, std::vector::iterator>>&&
84 | is_range_iterator_v, std::vector::const_iterator>>&&
85 | "Basic range iterator does not abide by the range iterator contract."
86 | );
87 | };
--------------------------------------------------------------------------------
/query/range_iterator_contract.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // 1. Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // 2. Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // 3. Neither the name of mosquitto nor the names of its
13 | // contributors may be used to endorse or promote products derived from
14 | // this software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | // POSSIBILITY OF SUCH DAMAGE.
27 | //
28 | #pragma once
29 | #include
30 | #include
31 |
32 | // We implement a simple type-traits like template to check if an arbitrary type
33 | // abides by the range iterator contract.
34 | //
35 | namespace vtil::query
36 | {
37 | namespace impl
38 | {
39 | template
40 | static constexpr bool _is_range_iterator( bool )
41 | {
42 | using T = typename std::remove_cvref_t<_T>;
43 |
44 | /// Must a valid standard random-access iterator.
45 | // - T::operator+=();
46 | // - T::operator++();
47 | // - T::operator--();
48 | //
49 | using dist_type = decltype( std::declval() - std::declval() );
50 | using next_type = decltype( std::next( std::declval() ) );
51 | using prev_type = decltype( std::prev( std::declval() ) );
52 | using dec_type = decltype( --std::declval() );
53 | using inc_type = decltype( ++std::declval() );
54 | using ref_type = decltype( std::declval().operator*() );
55 | using ptr_type = decltype( std::declval().operator->() );
56 |
57 | // Must have a public member called .container that is of type T::container_type*.
58 | // - T::container_type* T::container;
59 | //
60 | using container_type_a = std::remove_pointer_t().container )>;
61 | using container_type_b = typename T::container_type;
62 | if ( !std::is_same_v )
63 | return false;
64 |
65 | // Must have the basic comparison checks implemented.
66 | // - bool T::operator==(const T& o);
67 | // - bool T::operator!=(const T& o);
68 | //
69 | using comparison_assertation_1 = decltype( bool( std::declval() == std::declval