├── .gitattributes ├── .gitignore ├── README.md ├── x64-virtualmachine.sln └── x64-virtualmachine ├── compiler_helper.hpp ├── disasm.cpp ├── disasm.hpp ├── entry.cpp ├── fmt ├── chrono.h ├── color.h ├── compile.h ├── core.h ├── format-inl.h ├── format.cc ├── format.h ├── locale.h ├── ostream.h ├── posix.cc ├── posix.h ├── printf.h ├── ranges.h └── safe-duration-cast.h ├── global.cpp ├── global.hpp ├── handler_add.cpp ├── handler_add.hpp ├── handler_add_byte.cpp ├── handler_add_byte.hpp ├── handler_add_displaced_destination.cpp ├── handler_add_displaced_destination.hpp ├── handler_add_displaced_source.cpp ├── handler_add_displaced_source.hpp ├── handler_unknown.cpp ├── handler_unknown.hpp ├── handlers.hpp ├── instruction.cpp ├── instruction.hpp ├── instruction_modrm.hpp ├── instruction_opcode.cpp ├── instruction_opcode.hpp ├── instruction_operand.cpp ├── instruction_operand.hpp ├── instruction_prefix.cpp ├── instruction_prefix.hpp ├── instruction_rex.hpp ├── loggr.hpp ├── numerical_helper.hpp ├── register.cpp ├── register.hpp ├── spinner.hpp ├── virtual_machine.cpp ├── virtual_machine.hpp ├── virtual_memory.cpp ├── virtual_memory.hpp ├── virtual_section.cpp ├── virtual_section.hpp ├── virtual_stack.cpp ├── virtual_stack.hpp ├── vm_test.hpp ├── x64-virtualmachine.vcxproj └── x64-virtualmachine.vcxproj.filters /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # x64-vm 2 | x86-64 virtual machine and disassembler, it's unfinished and only handles a few ADD instruction variants. This is the result of self-hatred, the intel reference manual and 7 days without internet. 3 | 4 | # Features 5 | 6 | + Virtual stack 7 | + Virtual memory (Virtual pages, handles pagefault) 8 | + Virtual registers 9 | -------------------------------------------------------------------------------- /x64-virtualmachine.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27428.2015 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x64-virtualmachine", "x64-virtualmachine\x64-virtualmachine.vcxproj", "{D974C97F-A6D1-4D3F-94E6-0C6D1B0152D7}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {D974C97F-A6D1-4D3F-94E6-0C6D1B0152D7}.Debug|x64.ActiveCfg = Debug|x64 17 | {D974C97F-A6D1-4D3F-94E6-0C6D1B0152D7}.Debug|x64.Build.0 = Debug|x64 18 | {D974C97F-A6D1-4D3F-94E6-0C6D1B0152D7}.Debug|x86.ActiveCfg = Debug|Win32 19 | {D974C97F-A6D1-4D3F-94E6-0C6D1B0152D7}.Debug|x86.Build.0 = Debug|Win32 20 | {D974C97F-A6D1-4D3F-94E6-0C6D1B0152D7}.Release|x64.ActiveCfg = Release|x64 21 | {D974C97F-A6D1-4D3F-94E6-0C6D1B0152D7}.Release|x64.Build.0 = Release|x64 22 | {D974C97F-A6D1-4D3F-94E6-0C6D1B0152D7}.Release|x86.ActiveCfg = Release|Win32 23 | {D974C97F-A6D1-4D3F-94E6-0C6D1B0152D7}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {378CFD4A-EF70-4AF4-88C9-0EEB34C47F38} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /x64-virtualmachine/compiler_helper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace compiler 4 | { 5 | namespace detail 6 | { 7 | template 8 | void unreferenced_variable(T val) 9 | { 10 | static_cast(val); 11 | } 12 | 13 | template 14 | void unreferenced_variable(T val, Rest... rest) 15 | { 16 | compiler::detail::unreferenced_variable(val); 17 | compiler::detail::unreferenced_variable(rest...); 18 | } 19 | } 20 | 21 | template 22 | void unreferenced_variable(Rest... rest) 23 | { 24 | compiler::detail::unreferenced_variable(rest...); 25 | } 26 | } -------------------------------------------------------------------------------- /x64-virtualmachine/disasm.cpp: -------------------------------------------------------------------------------- 1 | // STD 2 | #include 3 | 4 | // x86 5 | #include "disasm.hpp" 6 | #include "instruction_prefix.hpp" 7 | #include "instruction_rex.hpp" 8 | #include "instruction_opcode.hpp" 9 | #include "instruction_operand.hpp" 10 | #include "instruction_modrm.hpp" 11 | 12 | std::uint8_t* x86::disassembler::buffer() 13 | { 14 | return this->m_buffer.data(); 15 | } 16 | 17 | size_t x86::disassembler::buffer_size() 18 | { 19 | return this->m_buffer.size(); 20 | } 21 | 22 | void x86::disassembler::handle_opcode(x86::instruction& instr, std::uint8_t*& buffer) 23 | { 24 | // HANDLE OPCODE INSTRUCTION 25 | 26 | // SAVE FIRST BYTE, TODO: MULTIPLE BYTE OPCODES 27 | instr.opcode().buffer().emplace_back(*buffer); 28 | ++buffer; 29 | 30 | // SET OPCODE INIT 31 | instr.opcode_initialised() = true; 32 | } 33 | 34 | void x86::disassembler::handle_operand(x86::instruction& instr, std::uint8_t*& buffer) 35 | { 36 | // HANDLE OPERAND DATA 37 | const auto search = x86::operand::info.find(instr.opcode().as()); 38 | 39 | // FOUND OPERAND SIZE 40 | if (search != x86::operand::info.end()) 41 | { 42 | // HARDCODED OPERAND INFORMATION 43 | 44 | const auto info = search->second; 45 | auto size = info.size; 46 | 47 | // IF MODRM EXISTS, PARSE MODE AND ADD TO SIZE 48 | if (info.modrm) 49 | { 50 | size += reinterpret_cast(buffer)->data_size(); 51 | } 52 | 53 | // SAVE ALL OPERAND BYTES 54 | for (size_t i = 0; i < size; i++, buffer++) 55 | instr.operand().buffer().emplace_back(*buffer); 56 | } 57 | 58 | // SET OPERAND INIT 59 | instr.operand_initialised() = true; 60 | } 61 | 62 | void x86::disassembler::handle_prefix(x86::instruction& instr, std::uint8_t*& buffer) 63 | { 64 | // HANDLE LEGACY PREFIX 65 | for (size_t i = 0; i < 4; i++) 66 | { 67 | // IF LEGACY PREFIX IS FOUND, SAVE IT AND CONTINUE ITERATION 68 | // SKIP IF WE ALREADY HAVE SAVED FOUR DIFFERENT PREFIXES (ONE FROM EACH GROUP) 69 | if (x86::prefix::is(*buffer)) 70 | { 71 | // SAVE LEGACY PREFIX BYTE 72 | instr.prefix().append(*buffer); 73 | ++buffer; 74 | continue; 75 | } 76 | else 77 | { 78 | // STOP WHEN NO PREFIX WAS FOUND 79 | break; 80 | } 81 | } 82 | 83 | // SET INIT STATUS 84 | instr.prefix_initialised() = true; 85 | } 86 | 87 | void x86::disassembler::handle_rex(x86::instruction& instr, std::uint8_t*& buffer) 88 | { 89 | // HANDLE REX BYTE 90 | auto rex = reinterpret_cast(buffer); 91 | 92 | // 0100, REX IDENTIFIER 93 | if (rex->id == 0x04) 94 | { 95 | // SAVE REX PREFIX 96 | instr.rex() = *rex; 97 | 98 | // GO TO NEXT BYTE 99 | ++buffer; 100 | } 101 | 102 | // SET INIT STATUS 103 | instr.rex_initialised() = true; 104 | } 105 | -------------------------------------------------------------------------------- /x64-virtualmachine/disasm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | #include 6 | 7 | // x86 8 | #include "instruction.hpp" 9 | 10 | 11 | // BASE DISASSEMBLY CLASS 12 | namespace x86 13 | { 14 | class disassembler 15 | { 16 | public: 17 | template 18 | disassembler(T(&buffer)[N]) : m_buffer(buffer, buffer + N) {} 19 | 20 | disassembler(std::vector buffer) : m_buffer(buffer) {} 21 | 22 | // ACCESSORS 23 | std::uint8_t* buffer(); 24 | size_t buffer_size(); 25 | 26 | // INSTRUCTION ITERATOR 27 | template 28 | void iterate(T offset, Fn callback) 29 | { 30 | for (auto instruction_pointer = this->buffer() + offset; 31 | instruction_pointer < this->buffer() + this->buffer_size();) 32 | { 33 | x86::instruction instr{}; 34 | 35 | // SAVE START TO CALCULATE SIZE 36 | auto start = instruction_pointer; 37 | 38 | // CHECK FOR PREFIX PRESENCE 39 | if (!instr.prefix_initialised()) 40 | { 41 | // HANDLE PREFIX 42 | x86::disassembler::handle_prefix(instr, instruction_pointer); 43 | } 44 | 45 | // CHECK FOR REX PREFIX 46 | if (!instr.rex_initialised()) 47 | { 48 | // HANDLE REX PREFIX 49 | x86::disassembler::handle_rex(instr, instruction_pointer); 50 | } 51 | 52 | // READ OPCODE 53 | if (!instr.opcode_initialised()) 54 | { 55 | x86::disassembler::handle_opcode(instr, instruction_pointer); 56 | } 57 | 58 | // HANDLE OPERAND FROM OPCODE 59 | if (!instr.operand_initialised()) 60 | { 61 | x86::disassembler::handle_operand(instr, instruction_pointer); 62 | } 63 | 64 | // CALCULATE SIZE 65 | instr.size() = static_cast(instruction_pointer - start); 66 | 67 | // RUN CALLBACK WITH DISASSEMBLED INSTRUCTION 68 | callback(instr, instruction_pointer); 69 | } 70 | } 71 | 72 | private: 73 | 74 | // DISASSEMBLY HANDLERS 75 | static void handle_opcode(x86::instruction& instr, std::uint8_t*& buffer); 76 | static void handle_operand(x86::instruction& instr, std::uint8_t*& buffer); 77 | static void handle_prefix(x86::instruction& instr, std::uint8_t*& buffer); 78 | static void handle_rex(x86::instruction& instr, std::uint8_t*& buffer); 79 | 80 | std::vector m_buffer; 81 | }; 82 | } -------------------------------------------------------------------------------- /x64-virtualmachine/entry.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmcall/x64-vm/68dbc32ff007981f30d3afddc7875f001055c8ae/x64-virtualmachine/entry.cpp -------------------------------------------------------------------------------- /x64-virtualmachine/fmt/color.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - color support 2 | // 3 | // Copyright (c) 2018 - present, Victor Zverovich and fmt contributors 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_COLOR_H_ 9 | #define FMT_COLOR_H_ 10 | 11 | #include "format.h" 12 | 13 | FMT_BEGIN_NAMESPACE 14 | 15 | enum class color : uint32_t { 16 | alice_blue = 0xF0F8FF, // rgb(240,248,255) 17 | antique_white = 0xFAEBD7, // rgb(250,235,215) 18 | aqua = 0x00FFFF, // rgb(0,255,255) 19 | aquamarine = 0x7FFFD4, // rgb(127,255,212) 20 | azure = 0xF0FFFF, // rgb(240,255,255) 21 | beige = 0xF5F5DC, // rgb(245,245,220) 22 | bisque = 0xFFE4C4, // rgb(255,228,196) 23 | black = 0x000000, // rgb(0,0,0) 24 | blanched_almond = 0xFFEBCD, // rgb(255,235,205) 25 | blue = 0x0000FF, // rgb(0,0,255) 26 | blue_violet = 0x8A2BE2, // rgb(138,43,226) 27 | brown = 0xA52A2A, // rgb(165,42,42) 28 | burly_wood = 0xDEB887, // rgb(222,184,135) 29 | cadet_blue = 0x5F9EA0, // rgb(95,158,160) 30 | chartreuse = 0x7FFF00, // rgb(127,255,0) 31 | chocolate = 0xD2691E, // rgb(210,105,30) 32 | coral = 0xFF7F50, // rgb(255,127,80) 33 | cornflower_blue = 0x6495ED, // rgb(100,149,237) 34 | cornsilk = 0xFFF8DC, // rgb(255,248,220) 35 | crimson = 0xDC143C, // rgb(220,20,60) 36 | cyan = 0x00FFFF, // rgb(0,255,255) 37 | dark_blue = 0x00008B, // rgb(0,0,139) 38 | dark_cyan = 0x008B8B, // rgb(0,139,139) 39 | dark_golden_rod = 0xB8860B, // rgb(184,134,11) 40 | dark_gray = 0xA9A9A9, // rgb(169,169,169) 41 | dark_green = 0x006400, // rgb(0,100,0) 42 | dark_khaki = 0xBDB76B, // rgb(189,183,107) 43 | dark_magenta = 0x8B008B, // rgb(139,0,139) 44 | dark_olive_green = 0x556B2F, // rgb(85,107,47) 45 | dark_orange = 0xFF8C00, // rgb(255,140,0) 46 | dark_orchid = 0x9932CC, // rgb(153,50,204) 47 | dark_red = 0x8B0000, // rgb(139,0,0) 48 | dark_salmon = 0xE9967A, // rgb(233,150,122) 49 | dark_sea_green = 0x8FBC8F, // rgb(143,188,143) 50 | dark_slate_blue = 0x483D8B, // rgb(72,61,139) 51 | dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) 52 | dark_turquoise = 0x00CED1, // rgb(0,206,209) 53 | dark_violet = 0x9400D3, // rgb(148,0,211) 54 | deep_pink = 0xFF1493, // rgb(255,20,147) 55 | deep_sky_blue = 0x00BFFF, // rgb(0,191,255) 56 | dim_gray = 0x696969, // rgb(105,105,105) 57 | dodger_blue = 0x1E90FF, // rgb(30,144,255) 58 | fire_brick = 0xB22222, // rgb(178,34,34) 59 | floral_white = 0xFFFAF0, // rgb(255,250,240) 60 | forest_green = 0x228B22, // rgb(34,139,34) 61 | fuchsia = 0xFF00FF, // rgb(255,0,255) 62 | gainsboro = 0xDCDCDC, // rgb(220,220,220) 63 | ghost_white = 0xF8F8FF, // rgb(248,248,255) 64 | gold = 0xFFD700, // rgb(255,215,0) 65 | golden_rod = 0xDAA520, // rgb(218,165,32) 66 | gray = 0x808080, // rgb(128,128,128) 67 | green = 0x008000, // rgb(0,128,0) 68 | green_yellow = 0xADFF2F, // rgb(173,255,47) 69 | honey_dew = 0xF0FFF0, // rgb(240,255,240) 70 | hot_pink = 0xFF69B4, // rgb(255,105,180) 71 | indian_red = 0xCD5C5C, // rgb(205,92,92) 72 | indigo = 0x4B0082, // rgb(75,0,130) 73 | ivory = 0xFFFFF0, // rgb(255,255,240) 74 | khaki = 0xF0E68C, // rgb(240,230,140) 75 | lavender = 0xE6E6FA, // rgb(230,230,250) 76 | lavender_blush = 0xFFF0F5, // rgb(255,240,245) 77 | lawn_green = 0x7CFC00, // rgb(124,252,0) 78 | lemon_chiffon = 0xFFFACD, // rgb(255,250,205) 79 | light_blue = 0xADD8E6, // rgb(173,216,230) 80 | light_coral = 0xF08080, // rgb(240,128,128) 81 | light_cyan = 0xE0FFFF, // rgb(224,255,255) 82 | light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) 83 | light_gray = 0xD3D3D3, // rgb(211,211,211) 84 | light_green = 0x90EE90, // rgb(144,238,144) 85 | light_pink = 0xFFB6C1, // rgb(255,182,193) 86 | light_salmon = 0xFFA07A, // rgb(255,160,122) 87 | light_sea_green = 0x20B2AA, // rgb(32,178,170) 88 | light_sky_blue = 0x87CEFA, // rgb(135,206,250) 89 | light_slate_gray = 0x778899, // rgb(119,136,153) 90 | light_steel_blue = 0xB0C4DE, // rgb(176,196,222) 91 | light_yellow = 0xFFFFE0, // rgb(255,255,224) 92 | lime = 0x00FF00, // rgb(0,255,0) 93 | lime_green = 0x32CD32, // rgb(50,205,50) 94 | linen = 0xFAF0E6, // rgb(250,240,230) 95 | magenta = 0xFF00FF, // rgb(255,0,255) 96 | maroon = 0x800000, // rgb(128,0,0) 97 | medium_aquamarine = 0x66CDAA, // rgb(102,205,170) 98 | medium_blue = 0x0000CD, // rgb(0,0,205) 99 | medium_orchid = 0xBA55D3, // rgb(186,85,211) 100 | medium_purple = 0x9370DB, // rgb(147,112,219) 101 | medium_sea_green = 0x3CB371, // rgb(60,179,113) 102 | medium_slate_blue = 0x7B68EE, // rgb(123,104,238) 103 | medium_spring_green = 0x00FA9A, // rgb(0,250,154) 104 | medium_turquoise = 0x48D1CC, // rgb(72,209,204) 105 | medium_violet_red = 0xC71585, // rgb(199,21,133) 106 | midnight_blue = 0x191970, // rgb(25,25,112) 107 | mint_cream = 0xF5FFFA, // rgb(245,255,250) 108 | misty_rose = 0xFFE4E1, // rgb(255,228,225) 109 | moccasin = 0xFFE4B5, // rgb(255,228,181) 110 | navajo_white = 0xFFDEAD, // rgb(255,222,173) 111 | navy = 0x000080, // rgb(0,0,128) 112 | old_lace = 0xFDF5E6, // rgb(253,245,230) 113 | olive = 0x808000, // rgb(128,128,0) 114 | olive_drab = 0x6B8E23, // rgb(107,142,35) 115 | orange = 0xFFA500, // rgb(255,165,0) 116 | orange_red = 0xFF4500, // rgb(255,69,0) 117 | orchid = 0xDA70D6, // rgb(218,112,214) 118 | pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) 119 | pale_green = 0x98FB98, // rgb(152,251,152) 120 | pale_turquoise = 0xAFEEEE, // rgb(175,238,238) 121 | pale_violet_red = 0xDB7093, // rgb(219,112,147) 122 | papaya_whip = 0xFFEFD5, // rgb(255,239,213) 123 | peach_puff = 0xFFDAB9, // rgb(255,218,185) 124 | peru = 0xCD853F, // rgb(205,133,63) 125 | pink = 0xFFC0CB, // rgb(255,192,203) 126 | plum = 0xDDA0DD, // rgb(221,160,221) 127 | powder_blue = 0xB0E0E6, // rgb(176,224,230) 128 | purple = 0x800080, // rgb(128,0,128) 129 | rebecca_purple = 0x663399, // rgb(102,51,153) 130 | red = 0xFF0000, // rgb(255,0,0) 131 | rosy_brown = 0xBC8F8F, // rgb(188,143,143) 132 | royal_blue = 0x4169E1, // rgb(65,105,225) 133 | saddle_brown = 0x8B4513, // rgb(139,69,19) 134 | salmon = 0xFA8072, // rgb(250,128,114) 135 | sandy_brown = 0xF4A460, // rgb(244,164,96) 136 | sea_green = 0x2E8B57, // rgb(46,139,87) 137 | sea_shell = 0xFFF5EE, // rgb(255,245,238) 138 | sienna = 0xA0522D, // rgb(160,82,45) 139 | silver = 0xC0C0C0, // rgb(192,192,192) 140 | sky_blue = 0x87CEEB, // rgb(135,206,235) 141 | slate_blue = 0x6A5ACD, // rgb(106,90,205) 142 | slate_gray = 0x708090, // rgb(112,128,144) 143 | snow = 0xFFFAFA, // rgb(255,250,250) 144 | spring_green = 0x00FF7F, // rgb(0,255,127) 145 | steel_blue = 0x4682B4, // rgb(70,130,180) 146 | tan = 0xD2B48C, // rgb(210,180,140) 147 | teal = 0x008080, // rgb(0,128,128) 148 | thistle = 0xD8BFD8, // rgb(216,191,216) 149 | tomato = 0xFF6347, // rgb(255,99,71) 150 | turquoise = 0x40E0D0, // rgb(64,224,208) 151 | violet = 0xEE82EE, // rgb(238,130,238) 152 | wheat = 0xF5DEB3, // rgb(245,222,179) 153 | white = 0xFFFFFF, // rgb(255,255,255) 154 | white_smoke = 0xF5F5F5, // rgb(245,245,245) 155 | yellow = 0xFFFF00, // rgb(255,255,0) 156 | yellow_green = 0x9ACD32 // rgb(154,205,50) 157 | }; // enum class color 158 | 159 | enum class terminal_color : uint8_t { 160 | black = 30, 161 | red, 162 | green, 163 | yellow, 164 | blue, 165 | magenta, 166 | cyan, 167 | white, 168 | bright_black = 90, 169 | bright_red, 170 | bright_green, 171 | bright_yellow, 172 | bright_blue, 173 | bright_magenta, 174 | bright_cyan, 175 | bright_white 176 | }; 177 | 178 | enum class emphasis : uint8_t { 179 | bold = 1, 180 | italic = 1 << 1, 181 | underline = 1 << 2, 182 | strikethrough = 1 << 3 183 | }; 184 | 185 | // rgb is a struct for red, green and blue colors. 186 | // Using the name "rgb" makes some editors show the color in a tooltip. 187 | struct rgb { 188 | FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} 189 | FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} 190 | FMT_CONSTEXPR rgb(uint32_t hex) 191 | : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} 192 | FMT_CONSTEXPR rgb(color hex) 193 | : r((uint32_t(hex) >> 16) & 0xFF), 194 | g((uint32_t(hex) >> 8) & 0xFF), 195 | b(uint32_t(hex) & 0xFF) {} 196 | uint8_t r; 197 | uint8_t g; 198 | uint8_t b; 199 | }; 200 | 201 | namespace internal { 202 | 203 | // color is a struct of either a rgb color or a terminal color. 204 | struct color_type { 205 | FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {} 206 | FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true), 207 | value{} { 208 | value.rgb_color = static_cast(rgb_color); 209 | } 210 | FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} { 211 | value.rgb_color = (static_cast(rgb_color.r) << 16) | 212 | (static_cast(rgb_color.g) << 8) | rgb_color.b; 213 | } 214 | FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(), 215 | value{} { 216 | value.term_color = static_cast(term_color); 217 | } 218 | bool is_rgb; 219 | union color_union { 220 | uint8_t term_color; 221 | uint32_t rgb_color; 222 | } value; 223 | }; 224 | } // namespace internal 225 | 226 | // Experimental text formatting support. 227 | class text_style { 228 | public: 229 | FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT 230 | : set_foreground_color(), 231 | set_background_color(), 232 | ems(em) {} 233 | 234 | FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { 235 | if (!set_foreground_color) { 236 | set_foreground_color = rhs.set_foreground_color; 237 | foreground_color = rhs.foreground_color; 238 | } else if (rhs.set_foreground_color) { 239 | if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) 240 | FMT_THROW(format_error("can't OR a terminal color")); 241 | foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; 242 | } 243 | 244 | if (!set_background_color) { 245 | set_background_color = rhs.set_background_color; 246 | background_color = rhs.background_color; 247 | } else if (rhs.set_background_color) { 248 | if (!background_color.is_rgb || !rhs.background_color.is_rgb) 249 | FMT_THROW(format_error("can't OR a terminal color")); 250 | background_color.value.rgb_color |= rhs.background_color.value.rgb_color; 251 | } 252 | 253 | ems = static_cast(static_cast(ems) | 254 | static_cast(rhs.ems)); 255 | return *this; 256 | } 257 | 258 | friend FMT_CONSTEXPR text_style operator|(text_style lhs, 259 | const text_style& rhs) { 260 | return lhs |= rhs; 261 | } 262 | 263 | FMT_CONSTEXPR text_style& operator&=(const text_style& rhs) { 264 | if (!set_foreground_color) { 265 | set_foreground_color = rhs.set_foreground_color; 266 | foreground_color = rhs.foreground_color; 267 | } else if (rhs.set_foreground_color) { 268 | if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) 269 | FMT_THROW(format_error("can't AND a terminal color")); 270 | foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; 271 | } 272 | 273 | if (!set_background_color) { 274 | set_background_color = rhs.set_background_color; 275 | background_color = rhs.background_color; 276 | } else if (rhs.set_background_color) { 277 | if (!background_color.is_rgb || !rhs.background_color.is_rgb) 278 | FMT_THROW(format_error("can't AND a terminal color")); 279 | background_color.value.rgb_color &= rhs.background_color.value.rgb_color; 280 | } 281 | 282 | ems = static_cast(static_cast(ems) & 283 | static_cast(rhs.ems)); 284 | return *this; 285 | } 286 | 287 | friend FMT_CONSTEXPR text_style operator&(text_style lhs, 288 | const text_style& rhs) { 289 | return lhs &= rhs; 290 | } 291 | 292 | FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT { 293 | return set_foreground_color; 294 | } 295 | FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT { 296 | return set_background_color; 297 | } 298 | FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT { 299 | return static_cast(ems) != 0; 300 | } 301 | FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT { 302 | assert(has_foreground() && "no foreground specified for this style"); 303 | return foreground_color; 304 | } 305 | FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT { 306 | assert(has_background() && "no background specified for this style"); 307 | return background_color; 308 | } 309 | FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT { 310 | assert(has_emphasis() && "no emphasis specified for this style"); 311 | return ems; 312 | } 313 | 314 | private: 315 | FMT_CONSTEXPR text_style(bool is_foreground, 316 | internal::color_type text_color) FMT_NOEXCEPT 317 | : set_foreground_color(), 318 | set_background_color(), 319 | ems() { 320 | if (is_foreground) { 321 | foreground_color = text_color; 322 | set_foreground_color = true; 323 | } else { 324 | background_color = text_color; 325 | set_background_color = true; 326 | } 327 | } 328 | 329 | friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground) 330 | FMT_NOEXCEPT; 331 | friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background) 332 | FMT_NOEXCEPT; 333 | 334 | internal::color_type foreground_color; 335 | internal::color_type background_color; 336 | bool set_foreground_color; 337 | bool set_background_color; 338 | emphasis ems; 339 | }; 340 | 341 | FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT { 342 | return text_style(/*is_foreground=*/true, foreground); 343 | } 344 | 345 | FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT { 346 | return text_style(/*is_foreground=*/false, background); 347 | } 348 | 349 | FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT { 350 | return text_style(lhs) | rhs; 351 | } 352 | 353 | namespace internal { 354 | 355 | template struct ansi_color_escape { 356 | FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color, 357 | const char* esc) FMT_NOEXCEPT { 358 | // If we have a terminal color, we need to output another escape code 359 | // sequence. 360 | if (!text_color.is_rgb) { 361 | bool is_background = esc == internal::data::background_color; 362 | uint32_t value = text_color.value.term_color; 363 | // Background ASCII codes are the same as the foreground ones but with 364 | // 10 more. 365 | if (is_background) value += 10u; 366 | 367 | std::size_t index = 0; 368 | buffer[index++] = static_cast('\x1b'); 369 | buffer[index++] = static_cast('['); 370 | 371 | if (value >= 100u) { 372 | buffer[index++] = static_cast('1'); 373 | value %= 100u; 374 | } 375 | buffer[index++] = static_cast('0' + value / 10u); 376 | buffer[index++] = static_cast('0' + value % 10u); 377 | 378 | buffer[index++] = static_cast('m'); 379 | buffer[index++] = static_cast('\0'); 380 | return; 381 | } 382 | 383 | for (int i = 0; i < 7; i++) { 384 | buffer[i] = static_cast(esc[i]); 385 | } 386 | rgb color(text_color.value.rgb_color); 387 | to_esc(color.r, buffer + 7, ';'); 388 | to_esc(color.g, buffer + 11, ';'); 389 | to_esc(color.b, buffer + 15, 'm'); 390 | buffer[19] = static_cast(0); 391 | } 392 | FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { 393 | uint8_t em_codes[4] = {}; 394 | uint8_t em_bits = static_cast(em); 395 | if (em_bits & static_cast(emphasis::bold)) em_codes[0] = 1; 396 | if (em_bits & static_cast(emphasis::italic)) em_codes[1] = 3; 397 | if (em_bits & static_cast(emphasis::underline)) em_codes[2] = 4; 398 | if (em_bits & static_cast(emphasis::strikethrough)) 399 | em_codes[3] = 9; 400 | 401 | std::size_t index = 0; 402 | for (int i = 0; i < 4; ++i) { 403 | if (!em_codes[i]) continue; 404 | buffer[index++] = static_cast('\x1b'); 405 | buffer[index++] = static_cast('['); 406 | buffer[index++] = static_cast('0' + em_codes[i]); 407 | buffer[index++] = static_cast('m'); 408 | } 409 | buffer[index++] = static_cast(0); 410 | } 411 | FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; } 412 | 413 | FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; } 414 | FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT { 415 | return buffer + std::strlen(buffer); 416 | } 417 | 418 | private: 419 | Char buffer[7u + 3u * 4u + 1u]; 420 | 421 | static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, 422 | char delimiter) FMT_NOEXCEPT { 423 | out[0] = static_cast('0' + c / 100); 424 | out[1] = static_cast('0' + c / 10 % 10); 425 | out[2] = static_cast('0' + c % 10); 426 | out[3] = static_cast(delimiter); 427 | } 428 | }; 429 | 430 | template 431 | FMT_CONSTEXPR ansi_color_escape make_foreground_color( 432 | internal::color_type foreground) FMT_NOEXCEPT { 433 | return ansi_color_escape(foreground, internal::data::foreground_color); 434 | } 435 | 436 | template 437 | FMT_CONSTEXPR ansi_color_escape make_background_color( 438 | internal::color_type background) FMT_NOEXCEPT { 439 | return ansi_color_escape(background, internal::data::background_color); 440 | } 441 | 442 | template 443 | FMT_CONSTEXPR ansi_color_escape make_emphasis(emphasis em) FMT_NOEXCEPT { 444 | return ansi_color_escape(em); 445 | } 446 | 447 | template 448 | inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT { 449 | std::fputs(chars, stream); 450 | } 451 | 452 | template <> 453 | inline void fputs(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT { 454 | std::fputws(chars, stream); 455 | } 456 | 457 | template inline void reset_color(FILE* stream) FMT_NOEXCEPT { 458 | fputs(internal::data::reset_color, stream); 459 | } 460 | 461 | template <> inline void reset_color(FILE* stream) FMT_NOEXCEPT { 462 | fputs(internal::data::wreset_color, stream); 463 | } 464 | 465 | template 466 | inline void reset_color(basic_memory_buffer& buffer) FMT_NOEXCEPT { 467 | const char* begin = data::reset_color; 468 | const char* end = begin + sizeof(data::reset_color) - 1; 469 | buffer.append(begin, end); 470 | } 471 | 472 | template 473 | std::basic_string vformat(const text_style& ts, 474 | basic_string_view format_str, 475 | basic_format_args > args) { 476 | basic_memory_buffer buffer; 477 | bool has_style = false; 478 | if (ts.has_emphasis()) { 479 | has_style = true; 480 | ansi_color_escape escape = make_emphasis(ts.get_emphasis()); 481 | buffer.append(escape.begin(), escape.end()); 482 | } 483 | if (ts.has_foreground()) { 484 | has_style = true; 485 | ansi_color_escape escape = 486 | make_foreground_color(ts.get_foreground()); 487 | buffer.append(escape.begin(), escape.end()); 488 | } 489 | if (ts.has_background()) { 490 | has_style = true; 491 | ansi_color_escape escape = 492 | make_background_color(ts.get_background()); 493 | buffer.append(escape.begin(), escape.end()); 494 | } 495 | internal::vformat_to(buffer, format_str, args); 496 | if (has_style) { 497 | reset_color(buffer); 498 | } 499 | return fmt::to_string(buffer); 500 | } 501 | } // namespace internal 502 | 503 | template > 504 | void vprint(std::FILE* f, const text_style& ts, const S& format, 505 | basic_format_args > args) { 506 | bool has_style = false; 507 | if (ts.has_emphasis()) { 508 | has_style = true; 509 | internal::fputs(internal::make_emphasis(ts.get_emphasis()), f); 510 | } 511 | if (ts.has_foreground()) { 512 | has_style = true; 513 | internal::fputs( 514 | internal::make_foreground_color(ts.get_foreground()), f); 515 | } 516 | if (ts.has_background()) { 517 | has_style = true; 518 | internal::fputs( 519 | internal::make_background_color(ts.get_background()), f); 520 | } 521 | vprint(f, format, args); 522 | if (has_style) { 523 | internal::reset_color(f); 524 | } 525 | } 526 | 527 | /** 528 | Formats a string and prints it to the specified file stream using ANSI 529 | escape sequences to specify text formatting. 530 | Example: 531 | fmt::print(fmt::emphasis::bold | fg(fmt::color::red), 532 | "Elapsed time: {0:.2f} seconds", 1.23); 533 | */ 534 | template ::value)> 536 | void print(std::FILE* f, const text_style& ts, const S& format_str, 537 | const Args&... args) { 538 | internal::check_format_string(format_str); 539 | using context = buffer_context >; 540 | format_arg_store as{args...}; 541 | vprint(f, ts, format_str, basic_format_args(as)); 542 | } 543 | 544 | /** 545 | Formats a string and prints it to stdout using ANSI escape sequences to 546 | specify text formatting. 547 | Example: 548 | fmt::print(fmt::emphasis::bold | fg(fmt::color::red), 549 | "Elapsed time: {0:.2f} seconds", 1.23); 550 | */ 551 | template ::value)> 553 | void print(const text_style& ts, const S& format_str, const Args&... args) { 554 | return print(stdout, ts, format_str, args...); 555 | } 556 | 557 | template > 558 | inline std::basic_string vformat( 559 | const text_style& ts, const S& format_str, 560 | basic_format_args > args) { 561 | return internal::vformat(ts, to_string_view(format_str), args); 562 | } 563 | 564 | /** 565 | \rst 566 | Formats arguments and returns the result as a string using ANSI 567 | escape sequences to specify text formatting. 568 | 569 | **Example**:: 570 | 571 | #include 572 | std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), 573 | "The answer is {}", 42); 574 | \endrst 575 | */ 576 | template > 577 | inline std::basic_string format(const text_style& ts, const S& format_str, 578 | const Args&... args) { 579 | return internal::vformat(ts, to_string_view(format_str), 580 | {internal::make_args_checked(format_str, args...)}); 581 | } 582 | 583 | FMT_END_NAMESPACE 584 | 585 | #endif // FMT_COLOR_H_ 586 | -------------------------------------------------------------------------------- /x64-virtualmachine/fmt/compile.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - experimental format string compilation 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich and fmt contributors 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_COMPILE_H_ 9 | #define FMT_COMPILE_H_ 10 | 11 | #include 12 | #include "format.h" 13 | 14 | FMT_BEGIN_NAMESPACE 15 | namespace internal { 16 | 17 | template struct format_part { 18 | public: 19 | struct named_argument_id { 20 | FMT_CONSTEXPR named_argument_id(internal::string_view_metadata id) 21 | : id(id) {} 22 | internal::string_view_metadata id; 23 | }; 24 | 25 | struct argument_id { 26 | FMT_CONSTEXPR argument_id() : argument_id(0u) {} 27 | 28 | FMT_CONSTEXPR argument_id(unsigned id) 29 | : which(which_arg_id::index), val(id) {} 30 | 31 | FMT_CONSTEXPR argument_id(internal::string_view_metadata id) 32 | : which(which_arg_id::named_index), val(id) {} 33 | 34 | enum class which_arg_id { index, named_index }; 35 | 36 | which_arg_id which; 37 | 38 | union value { 39 | FMT_CONSTEXPR value() : index(0u) {} 40 | FMT_CONSTEXPR value(unsigned id) : index(id) {} 41 | FMT_CONSTEXPR value(internal::string_view_metadata id) 42 | : named_index(id) {} 43 | 44 | unsigned index; 45 | internal::string_view_metadata named_index; 46 | } val; 47 | }; 48 | 49 | struct specification { 50 | FMT_CONSTEXPR specification() : arg_id(0u) {} 51 | FMT_CONSTEXPR specification(unsigned id) : arg_id(id) {} 52 | 53 | FMT_CONSTEXPR specification(internal::string_view_metadata id) 54 | : arg_id(id) {} 55 | 56 | argument_id arg_id; 57 | internal::dynamic_format_specs parsed_specs; 58 | }; 59 | 60 | FMT_CONSTEXPR format_part() 61 | : which(kind::argument_id), end_of_argument_id(0u), val(0u) {} 62 | 63 | FMT_CONSTEXPR format_part(internal::string_view_metadata text) 64 | : which(kind::text), end_of_argument_id(0u), val(text) {} 65 | 66 | FMT_CONSTEXPR format_part(unsigned id) 67 | : which(kind::argument_id), end_of_argument_id(0u), val(id) {} 68 | 69 | FMT_CONSTEXPR format_part(named_argument_id arg_id) 70 | : which(kind::named_argument_id), end_of_argument_id(0u), val(arg_id) {} 71 | 72 | FMT_CONSTEXPR format_part(specification spec) 73 | : which(kind::specification), end_of_argument_id(0u), val(spec) {} 74 | 75 | enum class kind { argument_id, named_argument_id, text, specification }; 76 | 77 | kind which; 78 | std::size_t end_of_argument_id; 79 | union value { 80 | FMT_CONSTEXPR value() : arg_id(0u) {} 81 | FMT_CONSTEXPR value(unsigned id) : arg_id(id) {} 82 | FMT_CONSTEXPR value(named_argument_id named_id) 83 | : named_arg_id(named_id.id) {} 84 | FMT_CONSTEXPR value(internal::string_view_metadata t) : text(t) {} 85 | FMT_CONSTEXPR value(specification s) : spec(s) {} 86 | unsigned arg_id; 87 | internal::string_view_metadata named_arg_id; 88 | internal::string_view_metadata text; 89 | specification spec; 90 | } val; 91 | }; 92 | 93 | template 94 | class format_preparation_handler : public internal::error_handler { 95 | private: 96 | using part = format_part; 97 | 98 | public: 99 | using iterator = typename basic_string_view::iterator; 100 | 101 | FMT_CONSTEXPR format_preparation_handler(basic_string_view format, 102 | PartsContainer& parts) 103 | : parts_(parts), format_(format), parse_context_(format) {} 104 | 105 | FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { 106 | if (begin == end) return; 107 | const auto offset = begin - format_.data(); 108 | const auto size = end - begin; 109 | parts_.push_back(part(string_view_metadata(offset, size))); 110 | } 111 | 112 | FMT_CONSTEXPR void on_arg_id() { 113 | parts_.push_back(part(parse_context_.next_arg_id())); 114 | } 115 | 116 | FMT_CONSTEXPR void on_arg_id(unsigned id) { 117 | parse_context_.check_arg_id(id); 118 | parts_.push_back(part(id)); 119 | } 120 | 121 | FMT_CONSTEXPR void on_arg_id(basic_string_view id) { 122 | const auto view = string_view_metadata(format_, id); 123 | const auto arg_id = typename part::named_argument_id(view); 124 | parts_.push_back(part(arg_id)); 125 | } 126 | 127 | FMT_CONSTEXPR void on_replacement_field(const Char* ptr) { 128 | parts_.back().end_of_argument_id = ptr - format_.begin(); 129 | } 130 | 131 | FMT_CONSTEXPR const Char* on_format_specs(const Char* begin, 132 | const Char* end) { 133 | const auto specs_offset = to_unsigned(begin - format_.begin()); 134 | 135 | using parse_context = basic_parse_context; 136 | internal::dynamic_format_specs parsed_specs; 137 | dynamic_specs_handler handler(parsed_specs, parse_context_); 138 | begin = parse_format_specs(begin, end, handler); 139 | 140 | if (*begin != '}') on_error("missing '}' in format string"); 141 | 142 | auto& last_part = parts_.back(); 143 | auto specs = last_part.which == part::kind::argument_id 144 | ? typename part::specification(last_part.val.arg_id) 145 | : typename part::specification(last_part.val.named_arg_id); 146 | specs.parsed_specs = parsed_specs; 147 | last_part = part(specs); 148 | last_part.end_of_argument_id = specs_offset; 149 | return begin; 150 | } 151 | 152 | private: 153 | PartsContainer& parts_; 154 | basic_string_view format_; 155 | basic_parse_context parse_context_; 156 | }; 157 | 158 | template 159 | class prepared_format { 160 | public: 161 | using char_type = char_t; 162 | using format_part_t = format_part; 163 | 164 | constexpr prepared_format(Format f) 165 | : format_(std::move(f)), parts_provider_(to_string_view(format_)) {} 166 | 167 | prepared_format() = delete; 168 | 169 | using context = buffer_context; 170 | 171 | template 172 | auto vformat_to(Range out, basic_format_args args) const -> 173 | typename Context::iterator { 174 | const auto format_view = internal::to_string_view(format_); 175 | basic_parse_context parse_ctx(format_view); 176 | Context ctx(out.begin(), args); 177 | 178 | const auto& parts = parts_provider_.parts(); 179 | for (auto part_it = parts.begin(); part_it != parts.end(); ++part_it) { 180 | const auto& part = *part_it; 181 | const auto& value = part.val; 182 | 183 | switch (part.which) { 184 | case format_part_t::kind::text: { 185 | const auto text = value.text.to_view(format_view.data()); 186 | auto output = ctx.out(); 187 | auto&& it = internal::reserve(output, text.size()); 188 | it = std::copy_n(text.begin(), text.size(), it); 189 | ctx.advance_to(output); 190 | } break; 191 | 192 | case format_part_t::kind::argument_id: { 193 | advance_parse_context_to_specification(parse_ctx, part); 194 | format_arg(parse_ctx, ctx, value.arg_id); 195 | } break; 196 | 197 | case format_part_t::kind::named_argument_id: { 198 | advance_parse_context_to_specification(parse_ctx, part); 199 | const auto named_arg_id = 200 | value.named_arg_id.to_view(format_view.data()); 201 | format_arg(parse_ctx, ctx, named_arg_id); 202 | } break; 203 | case format_part_t::kind::specification: { 204 | const auto& arg_id_value = value.spec.arg_id.val; 205 | const auto arg = value.spec.arg_id.which == 206 | format_part_t::argument_id::which_arg_id::index 207 | ? ctx.arg(arg_id_value.index) 208 | : ctx.arg(arg_id_value.named_index.to_view( 209 | to_string_view(format_).data())); 210 | 211 | auto specs = value.spec.parsed_specs; 212 | 213 | handle_dynamic_spec( 214 | specs.width, specs.width_ref, ctx, format_view.begin()); 215 | handle_dynamic_spec( 216 | specs.precision, specs.precision_ref, ctx, format_view.begin()); 217 | 218 | check_prepared_specs(specs, arg.type()); 219 | advance_parse_context_to_specification(parse_ctx, part); 220 | ctx.advance_to( 221 | visit_format_arg(arg_formatter(ctx, nullptr, &specs), arg)); 222 | } break; 223 | } 224 | } 225 | 226 | return ctx.out(); 227 | } 228 | 229 | private: 230 | void advance_parse_context_to_specification( 231 | basic_parse_context& parse_ctx, 232 | const format_part_t& part) const { 233 | const auto view = to_string_view(format_); 234 | const auto specification_begin = view.data() + part.end_of_argument_id; 235 | advance_to(parse_ctx, specification_begin); 236 | } 237 | 238 | template 239 | void format_arg(basic_parse_context& parse_ctx, Context& ctx, 240 | Id arg_id) const { 241 | parse_ctx.check_arg_id(arg_id); 242 | const auto stopped_at = 243 | visit_format_arg(arg_formatter(ctx), ctx.arg(arg_id)); 244 | ctx.advance_to(stopped_at); 245 | } 246 | 247 | template 248 | void check_prepared_specs(const basic_format_specs& specs, 249 | internal::type arg_type) const { 250 | internal::error_handler h; 251 | numeric_specs_checker checker(h, arg_type); 252 | if (specs.align == align::numeric) checker.require_numeric_argument(); 253 | if (specs.sign != sign::none) checker.check_sign(); 254 | if (specs.alt) checker.require_numeric_argument(); 255 | if (specs.precision >= 0) checker.check_precision(); 256 | } 257 | 258 | private: 259 | Format format_; 260 | PreparedPartsProvider parts_provider_; 261 | }; 262 | 263 | template struct part_counter { 264 | unsigned num_parts = 0; 265 | 266 | FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { 267 | if (begin != end) ++num_parts; 268 | } 269 | 270 | FMT_CONSTEXPR void on_arg_id() { ++num_parts; } 271 | FMT_CONSTEXPR void on_arg_id(unsigned) { ++num_parts; } 272 | FMT_CONSTEXPR void on_arg_id(basic_string_view) { ++num_parts; } 273 | 274 | FMT_CONSTEXPR void on_replacement_field(const Char*) {} 275 | 276 | FMT_CONSTEXPR const Char* on_format_specs(const Char* begin, 277 | const Char* end) { 278 | // Find the matching brace. 279 | unsigned braces_counter = 0; 280 | for (; begin != end; ++begin) { 281 | if (*begin == '{') { 282 | ++braces_counter; 283 | } else if (*begin == '}') { 284 | if (braces_counter == 0u) break; 285 | --braces_counter; 286 | } 287 | } 288 | return begin; 289 | } 290 | 291 | FMT_CONSTEXPR void on_error(const char*) {} 292 | }; 293 | 294 | template class compiletime_prepared_parts_type_provider { 295 | private: 296 | using char_type = char_t; 297 | 298 | static FMT_CONSTEXPR unsigned count_parts() { 299 | FMT_CONSTEXPR_DECL const auto text = to_string_view(Format{}); 300 | part_counter counter; 301 | internal::parse_format_string(text, counter); 302 | return counter.num_parts; 303 | } 304 | 305 | // Workaround for old compilers. Compiletime parts preparation will not be 306 | // performed with them anyway. 307 | #if FMT_USE_CONSTEXPR 308 | static FMT_CONSTEXPR_DECL const unsigned number_of_format_parts = 309 | compiletime_prepared_parts_type_provider::count_parts(); 310 | #else 311 | static const unsigned number_of_format_parts = 0u; 312 | #endif 313 | 314 | public: 315 | template struct format_parts_array { 316 | using value_type = format_part; 317 | 318 | FMT_CONSTEXPR format_parts_array() : arr{} {} 319 | 320 | FMT_CONSTEXPR value_type& operator[](unsigned ind) { return arr[ind]; } 321 | 322 | FMT_CONSTEXPR const value_type* begin() const { return arr; } 323 | FMT_CONSTEXPR const value_type* end() const { return begin() + N; } 324 | 325 | private: 326 | value_type arr[N]; 327 | }; 328 | 329 | struct empty { 330 | // Parts preparator will search for it 331 | using value_type = format_part; 332 | }; 333 | 334 | using type = conditional_t, empty>; 336 | }; 337 | 338 | template class compiletime_prepared_parts_collector { 339 | private: 340 | using format_part = typename Parts::value_type; 341 | 342 | public: 343 | FMT_CONSTEXPR explicit compiletime_prepared_parts_collector(Parts& parts) 344 | : parts_{parts}, counter_{0u} {} 345 | 346 | FMT_CONSTEXPR void push_back(format_part part) { parts_[counter_++] = part; } 347 | 348 | FMT_CONSTEXPR format_part& back() { return parts_[counter_ - 1]; } 349 | 350 | private: 351 | Parts& parts_; 352 | unsigned counter_; 353 | }; 354 | 355 | template 356 | FMT_CONSTEXPR PartsContainer prepare_parts(basic_string_view format) { 357 | PartsContainer parts; 358 | internal::parse_format_string( 359 | format, format_preparation_handler(format, parts)); 360 | return parts; 361 | } 362 | 363 | template 364 | FMT_CONSTEXPR PartsContainer 365 | prepare_compiletime_parts(basic_string_view format) { 366 | using collector = compiletime_prepared_parts_collector; 367 | 368 | PartsContainer parts; 369 | collector c(parts); 370 | internal::parse_format_string( 371 | format, format_preparation_handler(format, c)); 372 | return parts; 373 | } 374 | 375 | template class runtime_parts_provider { 376 | public: 377 | runtime_parts_provider() = delete; 378 | template 379 | runtime_parts_provider(basic_string_view format) 380 | : parts_(prepare_parts(format)) {} 381 | 382 | const PartsContainer& parts() const { return parts_; } 383 | 384 | private: 385 | PartsContainer parts_; 386 | }; 387 | 388 | template 389 | struct compiletime_parts_provider { 390 | compiletime_parts_provider() = delete; 391 | template 392 | FMT_CONSTEXPR compiletime_parts_provider(basic_string_view) {} 393 | 394 | const PartsContainer& parts() const { 395 | static FMT_CONSTEXPR_DECL const PartsContainer prepared_parts = 396 | prepare_compiletime_parts( 397 | internal::to_string_view(Format{})); 398 | 399 | return prepared_parts; 400 | } 401 | }; 402 | } // namespace internal 403 | 404 | #if FMT_USE_CONSTEXPR 405 | template ::value)> 407 | FMT_CONSTEXPR auto compile(S format_str) -> internal::prepared_format< 408 | S, 409 | internal::compiletime_parts_provider< 410 | S, 411 | typename internal::compiletime_prepared_parts_type_provider::type>, 412 | Args...> { 413 | return format_str; 414 | } 415 | #endif 416 | 417 | template 418 | auto compile(const Char (&format_str)[N]) -> internal::prepared_format< 419 | std::basic_string, 420 | internal::runtime_parts_provider>>, 421 | Args...> { 422 | return std::basic_string(format_str, N - 1); 423 | } 424 | 425 | template 427 | std::basic_string format(const CompiledFormat& cf, const Args&... args) { 428 | basic_memory_buffer buffer; 429 | using range = internal::buffer_range; 430 | using context = buffer_context; 431 | cf.template vformat_to(range(buffer), 432 | {make_format_args(args...)}); 433 | return to_string(buffer); 434 | } 435 | 436 | template 437 | OutputIt format_to(OutputIt out, const CompiledFormat& cf, 438 | const Args&... args) { 439 | using char_type = typename CompiledFormat::char_type; 440 | using range = internal::output_range; 441 | using context = format_context_t; 442 | return cf.template vformat_to( 443 | range(out), {make_format_args(args...)}); 444 | } 445 | 446 | template ::value)> 448 | format_to_n_result format_to_n(OutputIt out, size_t n, 449 | const CompiledFormat& cf, 450 | const Args&... args) { 451 | auto it = 452 | format_to(internal::truncating_iterator(out, n), cf, args...); 453 | return {it.base(), it.count()}; 454 | } 455 | 456 | template 457 | std::size_t formatted_size(const CompiledFormat& cf, const Args&... args) { 458 | return fmt::format_to( 459 | internal::counting_iterator(), 460 | cf, args...) 461 | .count(); 462 | } 463 | 464 | FMT_END_NAMESPACE 465 | 466 | #endif // FMT_COMPILE_H_ 467 | -------------------------------------------------------------------------------- /x64-virtualmachine/fmt/format.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #include "format-inl.h" 9 | 10 | FMT_BEGIN_NAMESPACE 11 | template struct FMT_API internal::basic_data; 12 | 13 | // Workaround a bug in MSVC2013 that prevents instantiation of grisu_format. 14 | bool (*instantiate_grisu_format)(double, internal::buffer&, int, unsigned, 15 | int&) = internal::grisu_format; 16 | 17 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 18 | template FMT_API internal::locale_ref::locale_ref(const std::locale& loc); 19 | template FMT_API std::locale internal::locale_ref::get() const; 20 | #endif 21 | 22 | // Explicit instantiations for char. 23 | 24 | template FMT_API char internal::thousands_sep_impl(locale_ref); 25 | template FMT_API char internal::decimal_point_impl(locale_ref); 26 | 27 | template FMT_API void internal::buffer::append(const char*, const char*); 28 | 29 | template FMT_API void internal::arg_map::init( 30 | const basic_format_args& args); 31 | 32 | template FMT_API std::string internal::vformat( 33 | string_view, basic_format_args); 34 | 35 | template FMT_API format_context::iterator internal::vformat_to( 36 | internal::buffer&, string_view, basic_format_args); 37 | 38 | template FMT_API char* internal::sprintf_format(double, internal::buffer&, 39 | sprintf_specs); 40 | template FMT_API char* internal::sprintf_format(long double, 41 | internal::buffer&, 42 | sprintf_specs); 43 | 44 | // Explicit instantiations for wchar_t. 45 | 46 | template FMT_API wchar_t internal::thousands_sep_impl(locale_ref); 47 | template FMT_API wchar_t internal::decimal_point_impl(locale_ref); 48 | 49 | template FMT_API void internal::buffer::append(const wchar_t*, 50 | const wchar_t*); 51 | 52 | template FMT_API void internal::arg_map::init( 53 | const basic_format_args&); 54 | 55 | template FMT_API std::wstring internal::vformat( 56 | wstring_view, basic_format_args); 57 | FMT_END_NAMESPACE 58 | -------------------------------------------------------------------------------- /x64-virtualmachine/fmt/locale.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::locale support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_LOCALE_H_ 9 | #define FMT_LOCALE_H_ 10 | 11 | #include 12 | #include "format.h" 13 | 14 | FMT_BEGIN_NAMESPACE 15 | 16 | namespace internal { 17 | template 18 | typename buffer_context::iterator vformat_to( 19 | const std::locale& loc, buffer& buf, 20 | basic_string_view format_str, 21 | basic_format_args> args) { 22 | using range = buffer_range; 23 | return vformat_to>(buf, to_string_view(format_str), args, 24 | internal::locale_ref(loc)); 25 | } 26 | 27 | template 28 | std::basic_string vformat(const std::locale& loc, 29 | basic_string_view format_str, 30 | basic_format_args> args) { 31 | basic_memory_buffer buffer; 32 | internal::vformat_to(loc, buffer, format_str, args); 33 | return fmt::to_string(buffer); 34 | } 35 | } // namespace internal 36 | 37 | template > 38 | inline std::basic_string vformat( 39 | const std::locale& loc, const S& format_str, 40 | basic_format_args> args) { 41 | return internal::vformat(loc, to_string_view(format_str), args); 42 | } 43 | 44 | template > 45 | inline std::basic_string format(const std::locale& loc, 46 | const S& format_str, Args&&... args) { 47 | return internal::vformat( 48 | loc, to_string_view(format_str), 49 | {internal::make_args_checked(format_str, args...)}); 50 | } 51 | 52 | template ::value, char_t>> 55 | inline OutputIt vformat_to(OutputIt out, const std::locale& loc, 56 | const S& format_str, 57 | format_args_t args) { 58 | using range = internal::output_range; 59 | return vformat_to>( 60 | range(out), to_string_view(format_str), args, internal::locale_ref(loc)); 61 | } 62 | 63 | template ::value&& 65 | internal::is_string::value)> 66 | inline OutputIt format_to(OutputIt out, const std::locale& loc, 67 | const S& format_str, Args&&... args) { 68 | internal::check_format_string(format_str); 69 | using context = format_context_t>; 70 | format_arg_store as{args...}; 71 | return vformat_to(out, loc, to_string_view(format_str), 72 | basic_format_args(as)); 73 | } 74 | 75 | FMT_END_NAMESPACE 76 | 77 | #endif // FMT_LOCALE_H_ 78 | -------------------------------------------------------------------------------- /x64-virtualmachine/fmt/ostream.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::ostream support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_OSTREAM_H_ 9 | #define FMT_OSTREAM_H_ 10 | 11 | #include 12 | #include "format.h" 13 | 14 | FMT_BEGIN_NAMESPACE 15 | namespace internal { 16 | 17 | template class formatbuf : public std::basic_streambuf { 18 | private: 19 | using int_type = typename std::basic_streambuf::int_type; 20 | using traits_type = typename std::basic_streambuf::traits_type; 21 | 22 | buffer& buffer_; 23 | 24 | public: 25 | formatbuf(buffer& buf) : buffer_(buf) {} 26 | 27 | protected: 28 | // The put-area is actually always empty. This makes the implementation 29 | // simpler and has the advantage that the streambuf and the buffer are always 30 | // in sync and sputc never writes into uninitialized memory. The obvious 31 | // disadvantage is that each call to sputc always results in a (virtual) call 32 | // to overflow. There is no disadvantage here for sputn since this always 33 | // results in a call to xsputn. 34 | 35 | int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { 36 | if (!traits_type::eq_int_type(ch, traits_type::eof())) 37 | buffer_.push_back(static_cast(ch)); 38 | return ch; 39 | } 40 | 41 | std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE { 42 | buffer_.append(s, s + count); 43 | return count; 44 | } 45 | }; 46 | 47 | template struct test_stream : std::basic_ostream { 48 | private: 49 | struct null; 50 | // Hide all operator<< from std::basic_ostream. 51 | void operator<<(null); 52 | }; 53 | 54 | // Checks if T has a user-defined operator<< (e.g. not a member of 55 | // std::ostream). 56 | template class is_streamable { 57 | private: 58 | template 59 | static decltype((void)(std::declval&>() 60 | << std::declval()), 61 | std::true_type()) 62 | test(int); 63 | 64 | template static std::false_type test(...); 65 | 66 | using result = decltype(test(0)); 67 | 68 | public: 69 | static const bool value = result::value; 70 | }; 71 | 72 | // Write the content of buf to os. 73 | template 74 | void write(std::basic_ostream& os, buffer& buf) { 75 | const Char* buf_data = buf.data(); 76 | using unsigned_streamsize = std::make_unsigned::type; 77 | unsigned_streamsize size = buf.size(); 78 | unsigned_streamsize max_size = 79 | to_unsigned((std::numeric_limits::max)()); 80 | do { 81 | unsigned_streamsize n = size <= max_size ? size : max_size; 82 | os.write(buf_data, static_cast(n)); 83 | buf_data += n; 84 | size -= n; 85 | } while (size != 0); 86 | } 87 | 88 | template 89 | void format_value(buffer& buf, const T& value) { 90 | formatbuf format_buf(buf); 91 | std::basic_ostream output(&format_buf); 92 | output.exceptions(std::ios_base::failbit | std::ios_base::badbit); 93 | output << value; 94 | buf.resize(buf.size()); 95 | } 96 | 97 | // Formats an object of type T that has an overloaded ostream operator<<. 98 | template 99 | struct fallback_formatter::value>> 100 | : formatter, Char> { 101 | template 102 | auto format(const T& value, Context& ctx) -> decltype(ctx.out()) { 103 | basic_memory_buffer buffer; 104 | format_value(buffer, value); 105 | basic_string_view str(buffer.data(), buffer.size()); 106 | return formatter, Char>::format(str, ctx); 107 | } 108 | }; 109 | } // namespace internal 110 | 111 | template 112 | void vprint(std::basic_ostream& os, basic_string_view format_str, 113 | basic_format_args> args) { 114 | basic_memory_buffer buffer; 115 | internal::vformat_to(buffer, format_str, args); 116 | internal::write(os, buffer); 117 | } 118 | 119 | /** 120 | \rst 121 | Prints formatted data to the stream *os*. 122 | 123 | **Example**:: 124 | 125 | fmt::print(cerr, "Don't {}!", "panic"); 126 | \endrst 127 | */ 128 | template ::value, char_t>> 130 | void print(std::basic_ostream& os, const S& format_str, Args&&... args) { 131 | vprint(os, to_string_view(format_str), 132 | {internal::make_args_checked(format_str, args...)}); 133 | } 134 | FMT_END_NAMESPACE 135 | 136 | #endif // FMT_OSTREAM_H_ 137 | -------------------------------------------------------------------------------- /x64-virtualmachine/fmt/posix.cc: -------------------------------------------------------------------------------- 1 | // A C++ interface to POSIX functions. 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | // Disable bogus MSVC warnings. 9 | #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER) 10 | # define _CRT_SECURE_NO_WARNINGS 11 | #endif 12 | 13 | #include "posix.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #ifndef _WIN32 20 | # include 21 | #else 22 | # ifndef WIN32_LEAN_AND_MEAN 23 | # define WIN32_LEAN_AND_MEAN 24 | # endif 25 | # include 26 | # include 27 | 28 | # define O_CREAT _O_CREAT 29 | # define O_TRUNC _O_TRUNC 30 | 31 | # ifndef S_IRUSR 32 | # define S_IRUSR _S_IREAD 33 | # endif 34 | 35 | # ifndef S_IWUSR 36 | # define S_IWUSR _S_IWRITE 37 | # endif 38 | 39 | # ifdef __MINGW32__ 40 | # define _SH_DENYNO 0x40 41 | # endif 42 | 43 | #endif // _WIN32 44 | 45 | #ifdef fileno 46 | # undef fileno 47 | #endif 48 | 49 | namespace { 50 | #ifdef _WIN32 51 | // Return type of read and write functions. 52 | typedef int RWResult; 53 | 54 | // On Windows the count argument to read and write is unsigned, so convert 55 | // it from size_t preventing integer overflow. 56 | inline unsigned convert_rwcount(std::size_t count) { 57 | return count <= UINT_MAX ? static_cast(count) : UINT_MAX; 58 | } 59 | #else 60 | // Return type of read and write functions. 61 | typedef ssize_t RWResult; 62 | 63 | inline std::size_t convert_rwcount(std::size_t count) { return count; } 64 | #endif 65 | } // namespace 66 | 67 | FMT_BEGIN_NAMESPACE 68 | 69 | buffered_file::~buffered_file() FMT_NOEXCEPT { 70 | if (file_ && FMT_SYSTEM(fclose(file_)) != 0) 71 | report_system_error(errno, "cannot close file"); 72 | } 73 | 74 | buffered_file::buffered_file(cstring_view filename, cstring_view mode) { 75 | FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 76 | nullptr); 77 | if (!file_) 78 | FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str())); 79 | } 80 | 81 | void buffered_file::close() { 82 | if (!file_) return; 83 | int result = FMT_SYSTEM(fclose(file_)); 84 | file_ = nullptr; 85 | if (result != 0) FMT_THROW(system_error(errno, "cannot close file")); 86 | } 87 | 88 | // A macro used to prevent expansion of fileno on broken versions of MinGW. 89 | #define FMT_ARGS 90 | 91 | int buffered_file::fileno() const { 92 | int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); 93 | if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor")); 94 | return fd; 95 | } 96 | 97 | file::file(cstring_view path, int oflag) { 98 | int mode = S_IRUSR | S_IWUSR; 99 | #if defined(_WIN32) && !defined(__MINGW32__) 100 | fd_ = -1; 101 | FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode)); 102 | #else 103 | FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); 104 | #endif 105 | if (fd_ == -1) 106 | FMT_THROW(system_error(errno, "cannot open file {}", path.c_str())); 107 | } 108 | 109 | file::~file() FMT_NOEXCEPT { 110 | // Don't retry close in case of EINTR! 111 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 112 | if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) 113 | report_system_error(errno, "cannot close file"); 114 | } 115 | 116 | void file::close() { 117 | if (fd_ == -1) return; 118 | // Don't retry close in case of EINTR! 119 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 120 | int result = FMT_POSIX_CALL(close(fd_)); 121 | fd_ = -1; 122 | if (result != 0) FMT_THROW(system_error(errno, "cannot close file")); 123 | } 124 | 125 | long long file::size() const { 126 | #ifdef _WIN32 127 | // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT 128 | // is less than 0x0500 as is the case with some default MinGW builds. 129 | // Both functions support large file sizes. 130 | DWORD size_upper = 0; 131 | HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); 132 | DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); 133 | if (size_lower == INVALID_FILE_SIZE) { 134 | DWORD error = GetLastError(); 135 | if (error != NO_ERROR) 136 | FMT_THROW(windows_error(GetLastError(), "cannot get file size")); 137 | } 138 | unsigned long long long_size = size_upper; 139 | return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; 140 | #else 141 | typedef struct stat Stat; 142 | Stat file_stat = Stat(); 143 | if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) 144 | FMT_THROW(system_error(errno, "cannot get file attributes")); 145 | static_assert(sizeof(long long) >= sizeof(file_stat.st_size), 146 | "return type of file::size is not large enough"); 147 | return file_stat.st_size; 148 | #endif 149 | } 150 | 151 | std::size_t file::read(void* buffer, std::size_t count) { 152 | RWResult result = 0; 153 | FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); 154 | if (result < 0) FMT_THROW(system_error(errno, "cannot read from file")); 155 | return internal::to_unsigned(result); 156 | } 157 | 158 | std::size_t file::write(const void* buffer, std::size_t count) { 159 | RWResult result = 0; 160 | FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); 161 | if (result < 0) FMT_THROW(system_error(errno, "cannot write to file")); 162 | return internal::to_unsigned(result); 163 | } 164 | 165 | file file::dup(int fd) { 166 | // Don't retry as dup doesn't return EINTR. 167 | // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html 168 | int new_fd = FMT_POSIX_CALL(dup(fd)); 169 | if (new_fd == -1) 170 | FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd)); 171 | return file(new_fd); 172 | } 173 | 174 | void file::dup2(int fd) { 175 | int result = 0; 176 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 177 | if (result == -1) { 178 | FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}", 179 | fd_, fd)); 180 | } 181 | } 182 | 183 | void file::dup2(int fd, error_code& ec) FMT_NOEXCEPT { 184 | int result = 0; 185 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 186 | if (result == -1) ec = error_code(errno); 187 | } 188 | 189 | void file::pipe(file& read_end, file& write_end) { 190 | // Close the descriptors first to make sure that assignments don't throw 191 | // and there are no leaks. 192 | read_end.close(); 193 | write_end.close(); 194 | int fds[2] = {}; 195 | #ifdef _WIN32 196 | // Make the default pipe capacity same as on Linux 2.6.11+. 197 | enum { DEFAULT_CAPACITY = 65536 }; 198 | int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); 199 | #else 200 | // Don't retry as the pipe function doesn't return EINTR. 201 | // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html 202 | int result = FMT_POSIX_CALL(pipe(fds)); 203 | #endif 204 | if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe")); 205 | // The following assignments don't throw because read_fd and write_fd 206 | // are closed. 207 | read_end = file(fds[0]); 208 | write_end = file(fds[1]); 209 | } 210 | 211 | buffered_file file::fdopen(const char* mode) { 212 | // Don't retry as fdopen doesn't return EINTR. 213 | FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode)); 214 | if (!f) 215 | FMT_THROW( 216 | system_error(errno, "cannot associate stream with file descriptor")); 217 | buffered_file bf(f); 218 | fd_ = -1; 219 | return bf; 220 | } 221 | 222 | long getpagesize() { 223 | #ifdef _WIN32 224 | SYSTEM_INFO si; 225 | GetSystemInfo(&si); 226 | return si.dwPageSize; 227 | #else 228 | long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); 229 | if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size")); 230 | return size; 231 | #endif 232 | } 233 | FMT_END_NAMESPACE 234 | -------------------------------------------------------------------------------- /x64-virtualmachine/fmt/posix.h: -------------------------------------------------------------------------------- 1 | // A C++ interface to POSIX functions. 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_POSIX_H_ 9 | #define FMT_POSIX_H_ 10 | 11 | #if defined(__MINGW32__) || defined(__CYGWIN__) 12 | // Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. 13 | # undef __STRICT_ANSI__ 14 | #endif 15 | 16 | #include 17 | #include // for O_RDONLY 18 | #include // for locale_t 19 | #include 20 | #include // for strtod_l 21 | 22 | #include 23 | 24 | #if defined __APPLE__ || defined(__FreeBSD__) 25 | # include // for LC_NUMERIC_MASK on OS X 26 | #endif 27 | 28 | #include "format.h" 29 | 30 | #ifndef FMT_POSIX 31 | # if defined(_WIN32) && !defined(__MINGW32__) 32 | // Fix warnings about deprecated symbols. 33 | # define FMT_POSIX(call) _##call 34 | # else 35 | # define FMT_POSIX(call) call 36 | # endif 37 | #endif 38 | 39 | // Calls to system functions are wrapped in FMT_SYSTEM for testability. 40 | #ifdef FMT_SYSTEM 41 | # define FMT_POSIX_CALL(call) FMT_SYSTEM(call) 42 | #else 43 | # define FMT_SYSTEM(call) call 44 | # ifdef _WIN32 45 | // Fix warnings about deprecated symbols. 46 | # define FMT_POSIX_CALL(call) ::_##call 47 | # else 48 | # define FMT_POSIX_CALL(call) ::call 49 | # endif 50 | #endif 51 | 52 | // Retries the expression while it evaluates to error_result and errno 53 | // equals to EINTR. 54 | #ifndef _WIN32 55 | # define FMT_RETRY_VAL(result, expression, error_result) \ 56 | do { \ 57 | result = (expression); \ 58 | } while (result == error_result && errno == EINTR) 59 | #else 60 | # define FMT_RETRY_VAL(result, expression, error_result) result = (expression) 61 | #endif 62 | 63 | #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) 64 | 65 | FMT_BEGIN_NAMESPACE 66 | 67 | /** 68 | \rst 69 | A reference to a null-terminated string. It can be constructed from a C 70 | string or ``std::string``. 71 | 72 | You can use one of the following type aliases for common character types: 73 | 74 | +---------------+-----------------------------+ 75 | | Type | Definition | 76 | +===============+=============================+ 77 | | cstring_view | basic_cstring_view | 78 | +---------------+-----------------------------+ 79 | | wcstring_view | basic_cstring_view | 80 | +---------------+-----------------------------+ 81 | 82 | This class is most useful as a parameter type to allow passing 83 | different types of strings to a function, for example:: 84 | 85 | template 86 | std::string format(cstring_view format_str, const Args & ... args); 87 | 88 | format("{}", 42); 89 | format(std::string("{}"), 42); 90 | \endrst 91 | */ 92 | template class basic_cstring_view { 93 | private: 94 | const Char* data_; 95 | 96 | public: 97 | /** Constructs a string reference object from a C string. */ 98 | basic_cstring_view(const Char* s) : data_(s) {} 99 | 100 | /** 101 | \rst 102 | Constructs a string reference from an ``std::string`` object. 103 | \endrst 104 | */ 105 | basic_cstring_view(const std::basic_string& s) : data_(s.c_str()) {} 106 | 107 | /** Returns the pointer to a C string. */ 108 | const Char* c_str() const { return data_; } 109 | }; 110 | 111 | using cstring_view = basic_cstring_view; 112 | using wcstring_view = basic_cstring_view; 113 | 114 | // An error code. 115 | class error_code { 116 | private: 117 | int value_; 118 | 119 | public: 120 | explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {} 121 | 122 | int get() const FMT_NOEXCEPT { return value_; } 123 | }; 124 | 125 | // A buffered file. 126 | class buffered_file { 127 | private: 128 | FILE* file_; 129 | 130 | friend class file; 131 | 132 | explicit buffered_file(FILE* f) : file_(f) {} 133 | 134 | public: 135 | // Constructs a buffered_file object which doesn't represent any file. 136 | buffered_file() FMT_NOEXCEPT : file_(nullptr) {} 137 | 138 | // Destroys the object closing the file it represents if any. 139 | FMT_API ~buffered_file() FMT_NOEXCEPT; 140 | 141 | private: 142 | buffered_file(const buffered_file&) = delete; 143 | void operator=(const buffered_file&) = delete; 144 | 145 | public: 146 | buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) { 147 | other.file_ = nullptr; 148 | } 149 | 150 | buffered_file& operator=(buffered_file&& other) { 151 | close(); 152 | file_ = other.file_; 153 | other.file_ = nullptr; 154 | return *this; 155 | } 156 | 157 | // Opens a file. 158 | FMT_API buffered_file(cstring_view filename, cstring_view mode); 159 | 160 | // Closes the file. 161 | FMT_API void close(); 162 | 163 | // Returns the pointer to a FILE object representing this file. 164 | FILE* get() const FMT_NOEXCEPT { return file_; } 165 | 166 | // We place parentheses around fileno to workaround a bug in some versions 167 | // of MinGW that define fileno as a macro. 168 | FMT_API int(fileno)() const; 169 | 170 | void vprint(string_view format_str, format_args args) { 171 | fmt::vprint(file_, format_str, args); 172 | } 173 | 174 | template 175 | inline void print(string_view format_str, const Args&... args) { 176 | vprint(format_str, make_format_args(args...)); 177 | } 178 | }; 179 | 180 | // A file. Closed file is represented by a file object with descriptor -1. 181 | // Methods that are not declared with FMT_NOEXCEPT may throw 182 | // fmt::system_error in case of failure. Note that some errors such as 183 | // closing the file multiple times will cause a crash on Windows rather 184 | // than an exception. You can get standard behavior by overriding the 185 | // invalid parameter handler with _set_invalid_parameter_handler. 186 | class file { 187 | private: 188 | int fd_; // File descriptor. 189 | 190 | // Constructs a file object with a given descriptor. 191 | explicit file(int fd) : fd_(fd) {} 192 | 193 | public: 194 | // Possible values for the oflag argument to the constructor. 195 | enum { 196 | RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. 197 | WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. 198 | RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. 199 | }; 200 | 201 | // Constructs a file object which doesn't represent any file. 202 | file() FMT_NOEXCEPT : fd_(-1) {} 203 | 204 | // Opens a file and constructs a file object representing this file. 205 | FMT_API file(cstring_view path, int oflag); 206 | 207 | private: 208 | file(const file&) = delete; 209 | void operator=(const file&) = delete; 210 | 211 | public: 212 | file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; } 213 | 214 | file& operator=(file&& other) { 215 | close(); 216 | fd_ = other.fd_; 217 | other.fd_ = -1; 218 | return *this; 219 | } 220 | 221 | // Destroys the object closing the file it represents if any. 222 | FMT_API ~file() FMT_NOEXCEPT; 223 | 224 | // Returns the file descriptor. 225 | int descriptor() const FMT_NOEXCEPT { return fd_; } 226 | 227 | // Closes the file. 228 | FMT_API void close(); 229 | 230 | // Returns the file size. The size has signed type for consistency with 231 | // stat::st_size. 232 | FMT_API long long size() const; 233 | 234 | // Attempts to read count bytes from the file into the specified buffer. 235 | FMT_API std::size_t read(void* buffer, std::size_t count); 236 | 237 | // Attempts to write count bytes from the specified buffer to the file. 238 | FMT_API std::size_t write(const void* buffer, std::size_t count); 239 | 240 | // Duplicates a file descriptor with the dup function and returns 241 | // the duplicate as a file object. 242 | FMT_API static file dup(int fd); 243 | 244 | // Makes fd be the copy of this file descriptor, closing fd first if 245 | // necessary. 246 | FMT_API void dup2(int fd); 247 | 248 | // Makes fd be the copy of this file descriptor, closing fd first if 249 | // necessary. 250 | FMT_API void dup2(int fd, error_code& ec) FMT_NOEXCEPT; 251 | 252 | // Creates a pipe setting up read_end and write_end file objects for reading 253 | // and writing respectively. 254 | FMT_API static void pipe(file& read_end, file& write_end); 255 | 256 | // Creates a buffered_file object associated with this file and detaches 257 | // this file object from the file. 258 | FMT_API buffered_file fdopen(const char* mode); 259 | }; 260 | 261 | // Returns the memory page size. 262 | long getpagesize(); 263 | 264 | #ifdef FMT_LOCALE 265 | // A "C" numeric locale. 266 | class Locale { 267 | private: 268 | # ifdef _WIN32 269 | using locale_t = _locale_t; 270 | 271 | enum { LC_NUMERIC_MASK = LC_NUMERIC }; 272 | 273 | static locale_t newlocale(int category_mask, const char* locale, locale_t) { 274 | return _create_locale(category_mask, locale); 275 | } 276 | 277 | static void freelocale(locale_t locale) { _free_locale(locale); } 278 | 279 | static double strtod_l(const char* nptr, char** endptr, _locale_t locale) { 280 | return _strtod_l(nptr, endptr, locale); 281 | } 282 | # endif 283 | 284 | locale_t locale_; 285 | 286 | Locale(const Locale&) = delete; 287 | void operator=(const Locale&) = delete; 288 | 289 | public: 290 | using type = locale_t; 291 | 292 | Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", nullptr)) { 293 | if (!locale_) FMT_THROW(system_error(errno, "cannot create locale")); 294 | } 295 | ~Locale() { freelocale(locale_); } 296 | 297 | type get() const { return locale_; } 298 | 299 | // Converts string to floating-point number and advances str past the end 300 | // of the parsed input. 301 | double strtod(const char*& str) const { 302 | char* end = nullptr; 303 | double result = strtod_l(str, &end, locale_); 304 | str = end; 305 | return result; 306 | } 307 | }; 308 | #endif // FMT_LOCALE 309 | FMT_END_NAMESPACE 310 | 311 | #endif // FMT_POSIX_H_ 312 | -------------------------------------------------------------------------------- /x64-virtualmachine/fmt/printf.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_PRINTF_H_ 9 | #define FMT_PRINTF_H_ 10 | 11 | #include // std::fill_n 12 | #include // std::numeric_limits 13 | 14 | #include "ostream.h" 15 | 16 | FMT_BEGIN_NAMESPACE 17 | namespace internal { 18 | 19 | // A helper function to suppress bogus "conditional expression is constant" 20 | // warnings. 21 | template inline T const_check(T value) { return value; } 22 | 23 | // Checks if a value fits in int - used to avoid warnings about comparing 24 | // signed and unsigned integers. 25 | template struct int_checker { 26 | template static bool fits_in_int(T value) { 27 | unsigned max = std::numeric_limits::max(); 28 | return value <= max; 29 | } 30 | static bool fits_in_int(bool) { return true; } 31 | }; 32 | 33 | template <> struct int_checker { 34 | template static bool fits_in_int(T value) { 35 | return value >= std::numeric_limits::min() && 36 | value <= std::numeric_limits::max(); 37 | } 38 | static bool fits_in_int(int) { return true; } 39 | }; 40 | 41 | class printf_precision_handler { 42 | public: 43 | template ::value)> 44 | int operator()(T value) { 45 | if (!int_checker::is_signed>::fits_in_int(value)) 46 | FMT_THROW(format_error("number is too big")); 47 | return (std::max)(static_cast(value), 0); 48 | } 49 | 50 | template ::value)> 51 | int operator()(T) { 52 | FMT_THROW(format_error("precision is not integer")); 53 | return 0; 54 | } 55 | }; 56 | 57 | // An argument visitor that returns true iff arg is a zero integer. 58 | class is_zero_int { 59 | public: 60 | template ::value)> 61 | bool operator()(T value) { 62 | return value == 0; 63 | } 64 | 65 | template ::value)> 66 | bool operator()(T) { 67 | return false; 68 | } 69 | }; 70 | 71 | template struct make_unsigned_or_bool : std::make_unsigned {}; 72 | 73 | template <> struct make_unsigned_or_bool { using type = bool; }; 74 | 75 | template class arg_converter { 76 | private: 77 | using char_type = typename Context::char_type; 78 | 79 | basic_format_arg& arg_; 80 | char_type type_; 81 | 82 | public: 83 | arg_converter(basic_format_arg& arg, char_type type) 84 | : arg_(arg), type_(type) {} 85 | 86 | void operator()(bool value) { 87 | if (type_ != 's') operator()(value); 88 | } 89 | 90 | template ::value)> 91 | void operator()(U value) { 92 | bool is_signed = type_ == 'd' || type_ == 'i'; 93 | using target_type = conditional_t::value, U, T>; 94 | if (const_check(sizeof(target_type) <= sizeof(int))) { 95 | // Extra casts are used to silence warnings. 96 | if (is_signed) { 97 | arg_ = internal::make_arg( 98 | static_cast(static_cast(value))); 99 | } else { 100 | using unsigned_type = typename make_unsigned_or_bool::type; 101 | arg_ = internal::make_arg( 102 | static_cast(static_cast(value))); 103 | } 104 | } else { 105 | if (is_signed) { 106 | // glibc's printf doesn't sign extend arguments of smaller types: 107 | // std::printf("%lld", -42); // prints "4294967254" 108 | // but we don't have to do the same because it's a UB. 109 | arg_ = internal::make_arg(static_cast(value)); 110 | } else { 111 | arg_ = internal::make_arg( 112 | static_cast::type>(value)); 113 | } 114 | } 115 | } 116 | 117 | template ::value)> 118 | void operator()(U) {} // No conversion needed for non-integral types. 119 | }; 120 | 121 | // Converts an integer argument to T for printf, if T is an integral type. 122 | // If T is void, the argument is converted to corresponding signed or unsigned 123 | // type depending on the type specifier: 'd' and 'i' - signed, other - 124 | // unsigned). 125 | template 126 | void convert_arg(basic_format_arg& arg, Char type) { 127 | visit_format_arg(arg_converter(arg, type), arg); 128 | } 129 | 130 | // Converts an integer argument to char for printf. 131 | template class char_converter { 132 | private: 133 | basic_format_arg& arg_; 134 | 135 | public: 136 | explicit char_converter(basic_format_arg& arg) : arg_(arg) {} 137 | 138 | template ::value)> 139 | void operator()(T value) { 140 | arg_ = internal::make_arg( 141 | static_cast(value)); 142 | } 143 | 144 | template ::value)> 145 | void operator()(T) {} // No conversion needed for non-integral types. 146 | }; 147 | 148 | // Checks if an argument is a valid printf width specifier and sets 149 | // left alignment if it is negative. 150 | template class printf_width_handler { 151 | private: 152 | using format_specs = basic_format_specs; 153 | 154 | format_specs& specs_; 155 | 156 | public: 157 | explicit printf_width_handler(format_specs& specs) : specs_(specs) {} 158 | 159 | template ::value)> 160 | unsigned operator()(T value) { 161 | auto width = static_cast>(value); 162 | if (internal::is_negative(value)) { 163 | specs_.align = align::left; 164 | width = 0 - width; 165 | } 166 | unsigned int_max = std::numeric_limits::max(); 167 | if (width > int_max) FMT_THROW(format_error("number is too big")); 168 | return static_cast(width); 169 | } 170 | 171 | template ::value)> 172 | unsigned operator()(T) { 173 | FMT_THROW(format_error("width is not integer")); 174 | return 0; 175 | } 176 | }; 177 | 178 | template 179 | void printf(buffer& buf, basic_string_view format, 180 | basic_format_args args) { 181 | Context(std::back_inserter(buf), format, args).format(); 182 | } 183 | 184 | template 185 | internal::truncating_iterator printf( 186 | internal::truncating_iterator it, basic_string_view format, 187 | basic_format_args args) { 188 | return Context(it, format, args).format(); 189 | } 190 | } // namespace internal 191 | 192 | using internal::printf; // For printing into memory_buffer. 193 | 194 | template class printf_arg_formatter; 195 | 196 | template class basic_printf_context; 197 | 198 | /** 199 | \rst 200 | The ``printf`` argument formatter. 201 | \endrst 202 | */ 203 | template 204 | class printf_arg_formatter : public internal::arg_formatter_base { 205 | public: 206 | using iterator = typename Range::iterator; 207 | 208 | private: 209 | using char_type = typename Range::value_type; 210 | using base = internal::arg_formatter_base; 211 | using context_type = basic_printf_context; 212 | 213 | context_type& context_; 214 | 215 | void write_null_pointer(char) { 216 | this->specs()->type = 0; 217 | this->write("(nil)"); 218 | } 219 | 220 | void write_null_pointer(wchar_t) { 221 | this->specs()->type = 0; 222 | this->write(L"(nil)"); 223 | } 224 | 225 | public: 226 | using format_specs = typename base::format_specs; 227 | 228 | /** 229 | \rst 230 | Constructs an argument formatter object. 231 | *buffer* is a reference to the output buffer and *specs* contains format 232 | specifier information for standard argument types. 233 | \endrst 234 | */ 235 | printf_arg_formatter(iterator iter, format_specs& specs, context_type& ctx) 236 | : base(Range(iter), &specs, internal::locale_ref()), context_(ctx) {} 237 | 238 | template ::value)> 239 | iterator operator()(T value) { 240 | // MSVC2013 fails to compile separate overloads for bool and char_type so 241 | // use std::is_same instead. 242 | if (std::is_same::value) { 243 | format_specs& fmt_specs = *this->specs(); 244 | if (fmt_specs.type != 's') return base::operator()(value ? 1 : 0); 245 | fmt_specs.type = 0; 246 | this->write(value != 0); 247 | } else if (std::is_same::value) { 248 | format_specs& fmt_specs = *this->specs(); 249 | if (fmt_specs.type && fmt_specs.type != 'c') 250 | return (*this)(static_cast(value)); 251 | fmt_specs.sign = sign::none; 252 | fmt_specs.alt = false; 253 | fmt_specs.align = align::right; 254 | return base::operator()(value); 255 | } else { 256 | return base::operator()(value); 257 | } 258 | return this->out(); 259 | } 260 | 261 | template ::value)> 262 | iterator operator()(T value) { 263 | return base::operator()(value); 264 | } 265 | 266 | /** Formats a null-terminated C string. */ 267 | iterator operator()(const char* value) { 268 | if (value) 269 | base::operator()(value); 270 | else if (this->specs()->type == 'p') 271 | write_null_pointer(char_type()); 272 | else 273 | this->write("(null)"); 274 | return this->out(); 275 | } 276 | 277 | /** Formats a null-terminated wide C string. */ 278 | iterator operator()(const wchar_t* value) { 279 | if (value) 280 | base::operator()(value); 281 | else if (this->specs()->type == 'p') 282 | write_null_pointer(char_type()); 283 | else 284 | this->write(L"(null)"); 285 | return this->out(); 286 | } 287 | 288 | iterator operator()(basic_string_view value) { 289 | return base::operator()(value); 290 | } 291 | 292 | iterator operator()(monostate value) { return base::operator()(value); } 293 | 294 | /** Formats a pointer. */ 295 | iterator operator()(const void* value) { 296 | if (value) return base::operator()(value); 297 | this->specs()->type = 0; 298 | write_null_pointer(char_type()); 299 | return this->out(); 300 | } 301 | 302 | /** Formats an argument of a custom (user-defined) type. */ 303 | iterator operator()(typename basic_format_arg::handle handle) { 304 | handle.format(context_.parse_context(), context_); 305 | return this->out(); 306 | } 307 | }; 308 | 309 | template struct printf_formatter { 310 | template 311 | auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 312 | return ctx.begin(); 313 | } 314 | 315 | template 316 | auto format(const T& value, FormatContext& ctx) -> decltype(ctx.out()) { 317 | internal::format_value(internal::get_container(ctx.out()), value); 318 | return ctx.out(); 319 | } 320 | }; 321 | 322 | /** This template formats data and writes the output to a writer. */ 323 | template class basic_printf_context { 324 | public: 325 | /** The character type for the output. */ 326 | using char_type = Char; 327 | using format_arg = basic_format_arg; 328 | template using formatter_type = printf_formatter; 329 | 330 | private: 331 | using format_specs = basic_format_specs; 332 | 333 | OutputIt out_; 334 | basic_format_args args_; 335 | basic_parse_context parse_ctx_; 336 | 337 | static void parse_flags(format_specs& specs, const Char*& it, 338 | const Char* end); 339 | 340 | // Returns the argument with specified index or, if arg_index is equal 341 | // to the maximum unsigned value, the next argument. 342 | format_arg get_arg(unsigned arg_index = std::numeric_limits::max()); 343 | 344 | // Parses argument index, flags and width and returns the argument index. 345 | unsigned parse_header(const Char*& it, const Char* end, format_specs& specs); 346 | 347 | public: 348 | /** 349 | \rst 350 | Constructs a ``printf_context`` object. References to the arguments and 351 | the writer are stored in the context object so make sure they have 352 | appropriate lifetimes. 353 | \endrst 354 | */ 355 | basic_printf_context(OutputIt out, basic_string_view format_str, 356 | basic_format_args args) 357 | : out_(out), args_(args), parse_ctx_(format_str) {} 358 | 359 | OutputIt out() { return out_; } 360 | void advance_to(OutputIt it) { out_ = it; } 361 | 362 | format_arg arg(unsigned id) const { return args_.get(id); } 363 | 364 | basic_parse_context& parse_context() { return parse_ctx_; } 365 | 366 | FMT_CONSTEXPR void on_error(const char* message) { 367 | parse_ctx_.on_error(message); 368 | } 369 | 370 | /** Formats stored arguments and writes the output to the range. */ 371 | template >> 373 | OutputIt format(); 374 | }; 375 | 376 | template 377 | void basic_printf_context::parse_flags(format_specs& specs, 378 | const Char*& it, 379 | const Char* end) { 380 | for (; it != end; ++it) { 381 | switch (*it) { 382 | case '-': 383 | specs.align = align::left; 384 | break; 385 | case '+': 386 | specs.sign = sign::plus; 387 | break; 388 | case '0': 389 | specs.fill[0] = '0'; 390 | break; 391 | case ' ': 392 | specs.sign = sign::space; 393 | break; 394 | case '#': 395 | specs.alt = true; 396 | break; 397 | default: 398 | return; 399 | } 400 | } 401 | } 402 | 403 | template 404 | typename basic_printf_context::format_arg 405 | basic_printf_context::get_arg(unsigned arg_index) { 406 | if (arg_index == std::numeric_limits::max()) 407 | arg_index = parse_ctx_.next_arg_id(); 408 | else 409 | parse_ctx_.check_arg_id(--arg_index); 410 | return internal::get_arg(*this, arg_index); 411 | } 412 | 413 | template 414 | unsigned basic_printf_context::parse_header( 415 | const Char*& it, const Char* end, format_specs& specs) { 416 | unsigned arg_index = std::numeric_limits::max(); 417 | char_type c = *it; 418 | if (c >= '0' && c <= '9') { 419 | // Parse an argument index (if followed by '$') or a width possibly 420 | // preceded with '0' flag(s). 421 | internal::error_handler eh; 422 | unsigned value = parse_nonnegative_int(it, end, eh); 423 | if (it != end && *it == '$') { // value is an argument index 424 | ++it; 425 | arg_index = value; 426 | } else { 427 | if (c == '0') specs.fill[0] = '0'; 428 | if (value != 0) { 429 | // Nonzero value means that we parsed width and don't need to 430 | // parse it or flags again, so return now. 431 | specs.width = value; 432 | return arg_index; 433 | } 434 | } 435 | } 436 | parse_flags(specs, it, end); 437 | // Parse width. 438 | if (it != end) { 439 | if (*it >= '0' && *it <= '9') { 440 | internal::error_handler eh; 441 | specs.width = parse_nonnegative_int(it, end, eh); 442 | } else if (*it == '*') { 443 | ++it; 444 | specs.width = visit_format_arg( 445 | internal::printf_width_handler(specs), get_arg()); 446 | } 447 | } 448 | return arg_index; 449 | } 450 | 451 | template 452 | template 453 | OutputIt basic_printf_context::format() { 454 | auto out = this->out(); 455 | const Char* start = parse_ctx_.begin(); 456 | const Char* end = parse_ctx_.end(); 457 | auto it = start; 458 | while (it != end) { 459 | char_type c = *it++; 460 | if (c != '%') continue; 461 | if (it != end && *it == c) { 462 | out = std::copy(start, it, out); 463 | start = ++it; 464 | continue; 465 | } 466 | out = std::copy(start, it - 1, out); 467 | 468 | format_specs specs; 469 | specs.align = align::right; 470 | 471 | // Parse argument index, flags and width. 472 | unsigned arg_index = parse_header(it, end, specs); 473 | 474 | // Parse precision. 475 | if (it != end && *it == '.') { 476 | ++it; 477 | c = it != end ? *it : 0; 478 | if ('0' <= c && c <= '9') { 479 | internal::error_handler eh; 480 | specs.precision = static_cast(parse_nonnegative_int(it, end, eh)); 481 | } else if (c == '*') { 482 | ++it; 483 | specs.precision = 484 | visit_format_arg(internal::printf_precision_handler(), get_arg()); 485 | } else { 486 | specs.precision = 0; 487 | } 488 | } 489 | 490 | format_arg arg = get_arg(arg_index); 491 | if (specs.alt && visit_format_arg(internal::is_zero_int(), arg)) 492 | specs.alt = false; 493 | if (specs.fill[0] == '0') { 494 | if (arg.is_arithmetic()) 495 | specs.align = align::numeric; 496 | else 497 | specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types. 498 | } 499 | 500 | // Parse length and convert the argument to the required type. 501 | c = it != end ? *it++ : 0; 502 | char_type t = it != end ? *it : 0; 503 | using internal::convert_arg; 504 | switch (c) { 505 | case 'h': 506 | if (t == 'h') { 507 | ++it; 508 | t = it != end ? *it : 0; 509 | convert_arg(arg, t); 510 | } else { 511 | convert_arg(arg, t); 512 | } 513 | break; 514 | case 'l': 515 | if (t == 'l') { 516 | ++it; 517 | t = it != end ? *it : 0; 518 | convert_arg(arg, t); 519 | } else { 520 | convert_arg(arg, t); 521 | } 522 | break; 523 | case 'j': 524 | convert_arg(arg, t); 525 | break; 526 | case 'z': 527 | convert_arg(arg, t); 528 | break; 529 | case 't': 530 | convert_arg(arg, t); 531 | break; 532 | case 'L': 533 | // printf produces garbage when 'L' is omitted for long double, no 534 | // need to do the same. 535 | break; 536 | default: 537 | --it; 538 | convert_arg(arg, c); 539 | } 540 | 541 | // Parse type. 542 | if (it == end) FMT_THROW(format_error("invalid format string")); 543 | specs.type = static_cast(*it++); 544 | if (arg.is_integral()) { 545 | // Normalize type. 546 | switch (specs.type) { 547 | case 'i': 548 | case 'u': 549 | specs.type = 'd'; 550 | break; 551 | case 'c': 552 | visit_format_arg(internal::char_converter(arg), 553 | arg); 554 | break; 555 | } 556 | } 557 | 558 | start = it; 559 | 560 | // Format argument. 561 | visit_format_arg(ArgFormatter(out, specs, *this), arg); 562 | } 563 | return std::copy(start, it, out); 564 | } 565 | 566 | template 567 | using basic_printf_context_t = 568 | basic_printf_context>, 569 | Char>; 570 | 571 | using printf_context = basic_printf_context_t; 572 | using wprintf_context = basic_printf_context_t; 573 | 574 | using printf_args = basic_format_args; 575 | using wprintf_args = basic_format_args; 576 | 577 | /** 578 | \rst 579 | Constructs an `~fmt::format_arg_store` object that contains references to 580 | arguments and can be implicitly converted to `~fmt::printf_args`. 581 | \endrst 582 | */ 583 | template 584 | inline format_arg_store make_printf_args( 585 | const Args&... args) { 586 | return {args...}; 587 | } 588 | 589 | /** 590 | \rst 591 | Constructs an `~fmt::format_arg_store` object that contains references to 592 | arguments and can be implicitly converted to `~fmt::wprintf_args`. 593 | \endrst 594 | */ 595 | template 596 | inline format_arg_store make_wprintf_args( 597 | const Args&... args) { 598 | return {args...}; 599 | } 600 | 601 | template > 602 | inline std::basic_string vsprintf( 603 | const S& format, basic_format_args> args) { 604 | basic_memory_buffer buffer; 605 | printf(buffer, to_string_view(format), args); 606 | return to_string(buffer); 607 | } 608 | 609 | /** 610 | \rst 611 | Formats arguments and returns the result as a string. 612 | 613 | **Example**:: 614 | 615 | std::string message = fmt::sprintf("The answer is %d", 42); 616 | \endrst 617 | */ 618 | template ::value, char_t>> 620 | inline std::basic_string sprintf(const S& format, const Args&... args) { 621 | using context = basic_printf_context_t; 622 | return vsprintf(to_string_view(format), {make_format_args(args...)}); 623 | } 624 | 625 | template > 626 | inline int vfprintf(std::FILE* f, const S& format, 627 | basic_format_args> args) { 628 | basic_memory_buffer buffer; 629 | printf(buffer, to_string_view(format), args); 630 | std::size_t size = buffer.size(); 631 | return std::fwrite(buffer.data(), sizeof(Char), size, f) < size 632 | ? -1 633 | : static_cast(size); 634 | } 635 | 636 | /** 637 | \rst 638 | Prints formatted data to the file *f*. 639 | 640 | **Example**:: 641 | 642 | fmt::fprintf(stderr, "Don't %s!", "panic"); 643 | \endrst 644 | */ 645 | template ::value, char_t>> 647 | inline int fprintf(std::FILE* f, const S& format, const Args&... args) { 648 | using context = basic_printf_context_t; 649 | return vfprintf(f, to_string_view(format), 650 | {make_format_args(args...)}); 651 | } 652 | 653 | template > 654 | inline int vprintf(const S& format, 655 | basic_format_args> args) { 656 | return vfprintf(stdout, to_string_view(format), args); 657 | } 658 | 659 | /** 660 | \rst 661 | Prints formatted data to ``stdout``. 662 | 663 | **Example**:: 664 | 665 | fmt::printf("Elapsed time: %.2f seconds", 1.23); 666 | \endrst 667 | */ 668 | template ::value)> 670 | inline int printf(const S& format_str, const Args&... args) { 671 | using context = basic_printf_context_t>; 672 | return vprintf(to_string_view(format_str), 673 | {make_format_args(args...)}); 674 | } 675 | 676 | template > 677 | inline int vfprintf(std::basic_ostream& os, const S& format, 678 | basic_format_args> args) { 679 | basic_memory_buffer buffer; 680 | printf(buffer, to_string_view(format), args); 681 | internal::write(os, buffer); 682 | return static_cast(buffer.size()); 683 | } 684 | 685 | /** Formats arguments and writes the output to the range. */ 686 | template > 689 | typename ArgFormatter::iterator vprintf(internal::buffer& out, 690 | basic_string_view format_str, 691 | basic_format_args args) { 692 | typename ArgFormatter::iterator iter(out); 693 | Context(iter, format_str, args).template format(); 694 | return iter; 695 | } 696 | 697 | /** 698 | \rst 699 | Prints formatted data to the stream *os*. 700 | 701 | **Example**:: 702 | 703 | fmt::fprintf(cerr, "Don't %s!", "panic"); 704 | \endrst 705 | */ 706 | template > 707 | inline int fprintf(std::basic_ostream& os, const S& format_str, 708 | const Args&... args) { 709 | using context = basic_printf_context_t; 710 | return vfprintf(os, to_string_view(format_str), 711 | {make_format_args(args...)}); 712 | } 713 | FMT_END_NAMESPACE 714 | 715 | #endif // FMT_PRINTF_H_ 716 | -------------------------------------------------------------------------------- /x64-virtualmachine/fmt/ranges.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - experimental range support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | // 8 | // Copyright (c) 2018 - present, Remotion (Igor Schulz) 9 | // All Rights Reserved 10 | // {fmt} support for ranges, containers and types tuple interface. 11 | 12 | #ifndef FMT_RANGES_H_ 13 | #define FMT_RANGES_H_ 14 | 15 | #include 16 | #include "format.h" 17 | 18 | // output only up to N items from the range. 19 | #ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT 20 | # define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 21 | #endif 22 | 23 | FMT_BEGIN_NAMESPACE 24 | 25 | template struct formatting_base { 26 | template 27 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 28 | return ctx.begin(); 29 | } 30 | }; 31 | 32 | template 33 | struct formatting_range : formatting_base { 34 | static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = 35 | FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the 36 | // range. 37 | Char prefix; 38 | Char delimiter; 39 | Char postfix; 40 | formatting_range() : prefix('{'), delimiter(','), postfix('}') {} 41 | static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; 42 | static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; 43 | }; 44 | 45 | template 46 | struct formatting_tuple : formatting_base { 47 | Char prefix; 48 | Char delimiter; 49 | Char postfix; 50 | formatting_tuple() : prefix('('), delimiter(','), postfix(')') {} 51 | static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; 52 | static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; 53 | }; 54 | 55 | namespace internal { 56 | 57 | template 58 | OutputIterator copy(const RangeT& range, OutputIterator out) { 59 | for (auto it = range.begin(), end = range.end(); it != end; ++it) 60 | *out++ = *it; 61 | return out; 62 | } 63 | 64 | template 65 | OutputIterator copy(const char* str, OutputIterator out) { 66 | while (*str) *out++ = *str++; 67 | return out; 68 | } 69 | 70 | template 71 | OutputIterator copy(char ch, OutputIterator out) { 72 | *out++ = ch; 73 | return out; 74 | } 75 | 76 | /// Return true value if T has std::string interface, like std::string_view. 77 | template class is_like_std_string { 78 | template 79 | static auto check(U* p) 80 | -> decltype((void)p->find('a'), p->length(), (void)p->data(), int()); 81 | template static void check(...); 82 | 83 | public: 84 | static FMT_CONSTEXPR_DECL const bool value = 85 | is_string::value || !std::is_void(nullptr))>::value; 86 | }; 87 | 88 | template 89 | struct is_like_std_string> : std::true_type {}; 90 | 91 | template struct conditional_helper {}; 92 | 93 | template struct is_range_ : std::false_type {}; 94 | 95 | #if !FMT_MSC_VER || FMT_MSC_VER > 1800 96 | template 97 | struct is_range_< 98 | T, conditional_t().begin()), 100 | decltype(std::declval().end())>, 101 | void>> : std::true_type {}; 102 | #endif 103 | 104 | /// tuple_size and tuple_element check. 105 | template class is_tuple_like_ { 106 | template 107 | static auto check(U* p) 108 | -> decltype(std::tuple_size::value, 109 | (void)std::declval::type>(), 110 | int()); 111 | template static void check(...); 112 | 113 | public: 114 | static FMT_CONSTEXPR_DECL const bool value = 115 | !std::is_void(nullptr))>::value; 116 | }; 117 | 118 | // Check for integer_sequence 119 | #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900 120 | template 121 | using integer_sequence = std::integer_sequence; 122 | template using index_sequence = std::index_sequence; 123 | template 124 | using make_index_sequence = std::make_index_sequence; 125 | #else 126 | template struct integer_sequence { 127 | using value_type = T; 128 | 129 | static FMT_CONSTEXPR std::size_t size() { return sizeof...(N); } 130 | }; 131 | 132 | template 133 | using index_sequence = integer_sequence; 134 | 135 | template 136 | struct make_integer_sequence : make_integer_sequence {}; 137 | template 138 | struct make_integer_sequence : integer_sequence {}; 139 | 140 | template 141 | using make_index_sequence = make_integer_sequence; 142 | #endif 143 | 144 | template 145 | void for_each(index_sequence, Tuple&& tup, F&& f) FMT_NOEXCEPT { 146 | using std::get; 147 | // using free function get(T) now. 148 | const int _[] = {0, ((void)f(get(tup)), 0)...}; 149 | (void)_; // blocks warnings 150 | } 151 | 152 | template 153 | FMT_CONSTEXPR make_index_sequence::value> get_indexes( 154 | T const&) { 155 | return {}; 156 | } 157 | 158 | template void for_each(Tuple&& tup, F&& f) { 159 | const auto indexes = get_indexes(tup); 160 | for_each(indexes, std::forward(tup), std::forward(f)); 161 | } 162 | 163 | template ::type>::value)> 165 | FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) { 166 | return add_space ? " {}" : "{}"; 167 | } 168 | 169 | template ::type>::value)> 171 | FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) { 172 | return add_space ? " \"{}\"" : "\"{}\""; 173 | } 174 | 175 | FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) { 176 | return add_space ? " \"{}\"" : "\"{}\""; 177 | } 178 | FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) { 179 | return add_space ? L" \"{}\"" : L"\"{}\""; 180 | } 181 | 182 | FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) { 183 | return add_space ? " '{}'" : "'{}'"; 184 | } 185 | FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) { 186 | return add_space ? L" '{}'" : L"'{}'"; 187 | } 188 | 189 | } // namespace internal 190 | 191 | template struct is_tuple_like { 192 | static FMT_CONSTEXPR_DECL const bool value = 193 | internal::is_tuple_like_::value && !internal::is_range_::value; 194 | }; 195 | 196 | template 197 | struct formatter::value>> { 198 | private: 199 | // C++11 generic lambda for format() 200 | template struct format_each { 201 | template void operator()(const T& v) { 202 | if (i > 0) { 203 | if (formatting.add_prepostfix_space) { 204 | *out++ = ' '; 205 | } 206 | out = internal::copy(formatting.delimiter, out); 207 | } 208 | out = format_to(out, 209 | internal::format_str_quoted( 210 | (formatting.add_delimiter_spaces && i > 0), v), 211 | v); 212 | ++i; 213 | } 214 | 215 | formatting_tuple& formatting; 216 | std::size_t& i; 217 | typename std::add_lvalue_reference().out())>::type out; 219 | }; 220 | 221 | public: 222 | formatting_tuple formatting; 223 | 224 | template 225 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 226 | return formatting.parse(ctx); 227 | } 228 | 229 | template 230 | auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) { 231 | auto out = ctx.out(); 232 | std::size_t i = 0; 233 | internal::copy(formatting.prefix, out); 234 | 235 | internal::for_each(values, format_each{formatting, i, out}); 236 | if (formatting.add_prepostfix_space) { 237 | *out++ = ' '; 238 | } 239 | internal::copy(formatting.postfix, out); 240 | 241 | return ctx.out(); 242 | } 243 | }; 244 | 245 | template struct is_range { 246 | static FMT_CONSTEXPR_DECL const bool value = 247 | internal::is_range_::value && 248 | !internal::is_like_std_string::value && 249 | !std::is_convertible>::value; 250 | }; 251 | 252 | template 253 | struct formatter::value>> { 255 | formatting_range formatting; 256 | 257 | template 258 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 259 | return formatting.parse(ctx); 260 | } 261 | 262 | template 263 | typename FormatContext::iterator format(const RangeT& values, 264 | FormatContext& ctx) { 265 | auto out = internal::copy(formatting.prefix, ctx.out()); 266 | std::size_t i = 0; 267 | for (auto it = values.begin(), end = values.end(); it != end; ++it) { 268 | if (i > 0) { 269 | if (formatting.add_prepostfix_space) *out++ = ' '; 270 | out = internal::copy(formatting.delimiter, out); 271 | } 272 | out = format_to(out, 273 | internal::format_str_quoted( 274 | (formatting.add_delimiter_spaces && i > 0), *it), 275 | *it); 276 | if (++i > formatting.range_length_limit) { 277 | out = format_to(out, " ... "); 278 | break; 279 | } 280 | } 281 | if (formatting.add_prepostfix_space) *out++ = ' '; 282 | return internal::copy(formatting.postfix, out); 283 | } 284 | }; 285 | 286 | FMT_END_NAMESPACE 287 | 288 | #endif // FMT_RANGES_H_ 289 | -------------------------------------------------------------------------------- /x64-virtualmachine/fmt/safe-duration-cast.h: -------------------------------------------------------------------------------- 1 | /* 2 | * For conversion between std::chrono::durations without undefined 3 | * behaviour or erroneous results. 4 | * This is a stripped down version of duration_cast, for inclusion in fmt. 5 | * See https://github.com/pauldreik/safe_duration_cast 6 | * 7 | * Copyright Paul Dreik 2019 8 | * 9 | * This file is licensed under the fmt license, see format.h 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "format.h" 18 | 19 | FMT_BEGIN_NAMESPACE 20 | 21 | namespace safe_duration_cast { 22 | 23 | template ::value && 25 | std::numeric_limits::is_signed == 26 | std::numeric_limits::is_signed)> 27 | FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { 28 | ec = 0; 29 | using F = std::numeric_limits; 30 | using T = std::numeric_limits; 31 | static_assert(F::is_integer, "From must be integral"); 32 | static_assert(T::is_integer, "To must be integral"); 33 | 34 | // A and B are both signed, or both unsigned. 35 | if (F::digits <= T::digits) { 36 | // From fits in To without any problem. 37 | } else { 38 | // From does not always fit in To, resort to a dynamic check. 39 | if (from < T::min() || from > T::max()) { 40 | // outside range. 41 | ec = 1; 42 | return {}; 43 | } 44 | } 45 | return static_cast(from); 46 | } 47 | 48 | /** 49 | * converts From to To, without loss. If the dynamic value of from 50 | * can't be converted to To without loss, ec is set. 51 | */ 52 | template ::value && 54 | std::numeric_limits::is_signed != 55 | std::numeric_limits::is_signed)> 56 | FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { 57 | ec = 0; 58 | using F = std::numeric_limits; 59 | using T = std::numeric_limits; 60 | static_assert(F::is_integer, "From must be integral"); 61 | static_assert(T::is_integer, "To must be integral"); 62 | 63 | if (F::is_signed && !T::is_signed) { 64 | // From may be negative, not allowed! 65 | if (from < 0) { 66 | ec = 1; 67 | return {}; 68 | } 69 | 70 | // From is positive. Can it always fit in To? 71 | if (F::digits <= T::digits) { 72 | // yes, From always fits in To. 73 | } else { 74 | // from may not fit in To, we have to do a dynamic check 75 | if (from > static_cast(T::max())) { 76 | ec = 1; 77 | return {}; 78 | } 79 | } 80 | } 81 | 82 | if (!F::is_signed && T::is_signed) { 83 | // can from be held in To? 84 | if (F::digits < T::digits) { 85 | // yes, From always fits in To. 86 | } else { 87 | // from may not fit in To, we have to do a dynamic check 88 | if (from > static_cast(T::max())) { 89 | // outside range. 90 | ec = 1; 91 | return {}; 92 | } 93 | } 94 | } 95 | 96 | // reaching here means all is ok for lossless conversion. 97 | return static_cast(from); 98 | 99 | } // function 100 | 101 | template ::value)> 103 | FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { 104 | ec = 0; 105 | return from; 106 | } // function 107 | 108 | // clang-format off 109 | /** 110 | * converts From to To if possible, otherwise ec is set. 111 | * 112 | * input | output 113 | * ---------------------------------|--------------- 114 | * NaN | NaN 115 | * Inf | Inf 116 | * normal, fits in output | converted (possibly lossy) 117 | * normal, does not fit in output | ec is set 118 | * subnormal | best effort 119 | * -Inf | -Inf 120 | */ 121 | // clang-format on 122 | template ::value)> 124 | FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) { 125 | ec = 0; 126 | using T = std::numeric_limits; 127 | static_assert(std::is_floating_point::value, "From must be floating"); 128 | static_assert(std::is_floating_point::value, "To must be floating"); 129 | 130 | // catch the only happy case 131 | if (std::isfinite(from)) { 132 | if (from >= T::lowest() && from <= T::max()) { 133 | return static_cast(from); 134 | } 135 | // not within range. 136 | ec = 1; 137 | return {}; 138 | } 139 | 140 | // nan and inf will be preserved 141 | return static_cast(from); 142 | } // function 143 | 144 | template ::value)> 146 | FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) { 147 | ec = 0; 148 | static_assert(std::is_floating_point::value, "From must be floating"); 149 | return from; 150 | } 151 | 152 | /** 153 | * safe duration cast between integral durations 154 | */ 155 | template ::value), 157 | FMT_ENABLE_IF(std::is_integral::value)> 158 | To safe_duration_cast(std::chrono::duration from, 159 | int& ec) { 160 | using From = std::chrono::duration; 161 | ec = 0; 162 | // the basic idea is that we need to convert from count() in the from type 163 | // to count() in the To type, by multiplying it with this: 164 | using Factor = std::ratio_divide; 165 | 166 | static_assert(Factor::num > 0, "num must be positive"); 167 | static_assert(Factor::den > 0, "den must be positive"); 168 | 169 | // the conversion is like this: multiply from.count() with Factor::num 170 | // /Factor::den and convert it to To::rep, all this without 171 | // overflow/underflow. let's start by finding a suitable type that can hold 172 | // both To, From and Factor::num 173 | using IntermediateRep = 174 | typename std::common_type::type; 176 | 177 | // safe conversion to IntermediateRep 178 | IntermediateRep count = 179 | lossless_integral_conversion(from.count(), ec); 180 | if (ec) { 181 | return {}; 182 | } 183 | // multiply with Factor::num without overflow or underflow 184 | if (Factor::num != 1) { 185 | constexpr auto max1 = 186 | std::numeric_limits::max() / Factor::num; 187 | if (count > max1) { 188 | ec = 1; 189 | return {}; 190 | } 191 | constexpr auto min1 = 192 | std::numeric_limits::min() / Factor::num; 193 | if (count < min1) { 194 | ec = 1; 195 | return {}; 196 | } 197 | count *= Factor::num; 198 | } 199 | 200 | // this can't go wrong, right? den>0 is checked earlier. 201 | if (Factor::den != 1) { 202 | count /= Factor::den; 203 | } 204 | // convert to the to type, safely 205 | using ToRep = typename To::rep; 206 | const ToRep tocount = lossless_integral_conversion(count, ec); 207 | if (ec) { 208 | return {}; 209 | } 210 | return To{tocount}; 211 | } 212 | 213 | /** 214 | * safe duration_cast between floating point durations 215 | */ 216 | template ::value), 218 | FMT_ENABLE_IF(std::is_floating_point::value)> 219 | To safe_duration_cast(std::chrono::duration from, 220 | int& ec) { 221 | using From = std::chrono::duration; 222 | ec = 0; 223 | if (std::isnan(from.count())) { 224 | // nan in, gives nan out. easy. 225 | return To{std::numeric_limits::quiet_NaN()}; 226 | } 227 | // maybe we should also check if from is denormal, and decide what to do about 228 | // it. 229 | 230 | // +-inf should be preserved. 231 | if (std::isinf(from.count())) { 232 | return To{from.count()}; 233 | } 234 | 235 | // the basic idea is that we need to convert from count() in the from type 236 | // to count() in the To type, by multiplying it with this: 237 | using Factor = std::ratio_divide; 238 | 239 | static_assert(Factor::num > 0, "num must be positive"); 240 | static_assert(Factor::den > 0, "den must be positive"); 241 | 242 | // the conversion is like this: multiply from.count() with Factor::num 243 | // /Factor::den and convert it to To::rep, all this without 244 | // overflow/underflow. let's start by finding a suitable type that can hold 245 | // both To, From and Factor::num 246 | using IntermediateRep = 247 | typename std::common_type::type; 249 | 250 | // force conversion of From::rep -> IntermediateRep to be safe, 251 | // even if it will never happen be narrowing in this context. 252 | IntermediateRep count = 253 | safe_float_conversion(from.count(), ec); 254 | if (ec) { 255 | return {}; 256 | } 257 | 258 | // multiply with Factor::num without overflow or underflow 259 | if (Factor::num != 1) { 260 | constexpr auto max1 = std::numeric_limits::max() / 261 | static_cast(Factor::num); 262 | if (count > max1) { 263 | ec = 1; 264 | return {}; 265 | } 266 | constexpr auto min1 = std::numeric_limits::lowest() / 267 | static_cast(Factor::num); 268 | if (count < min1) { 269 | ec = 1; 270 | return {}; 271 | } 272 | count *= static_cast(Factor::num); 273 | } 274 | 275 | // this can't go wrong, right? den>0 is checked earlier. 276 | if (Factor::den != 1) { 277 | using common_t = typename std::common_type::type; 278 | count /= static_cast(Factor::den); 279 | } 280 | 281 | // convert to the to type, safely 282 | using ToRep = typename To::rep; 283 | 284 | const ToRep tocount = safe_float_conversion(count, ec); 285 | if (ec) { 286 | return {}; 287 | } 288 | return To{tocount}; 289 | } 290 | 291 | } // namespace safe_duration_cast 292 | 293 | FMT_END_NAMESPACE 294 | -------------------------------------------------------------------------------- /x64-virtualmachine/global.cpp: -------------------------------------------------------------------------------- 1 | #include "global.hpp" 2 | 3 | loggr global::console = loggr(); -------------------------------------------------------------------------------- /x64-virtualmachine/global.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "loggr.hpp" 3 | 4 | namespace global 5 | { 6 | extern loggr console; 7 | } -------------------------------------------------------------------------------- /x64-virtualmachine/handler_add.cpp: -------------------------------------------------------------------------------- 1 | 2 | // VM 3 | #include "handler_add.hpp" 4 | #include "handler_add_displaced_source.hpp" 5 | #include "handler_add_displaced_destination.hpp" 6 | #include "handler_add_byte.hpp" 7 | 8 | // HELPER 9 | #include "compiler_helper.hpp" 10 | 11 | void vm::handler::add::handle(virtual_machine* vm, x86::instruction& instr) 12 | { 13 | // HANDLE ADD VARIANTS 14 | switch (instr.opcode().as()) 15 | { 16 | 17 | // DISPLACED SOURCE 18 | case x86::opcode::add_displaced_source: 19 | vm::handler::add::displaced_source(vm, instr); 20 | return; 21 | 22 | // NORMAL 23 | case x86::opcode::add_displaced_destination: 24 | vm::handler::add::displaced_destination(vm, instr); 25 | return; 26 | 27 | 28 | // BYTE 29 | case x86::opcode::add_byte: 30 | vm::handler::add::byte(vm, instr); 31 | return; 32 | 33 | default: 34 | throw std::exception("Unsupported ADD"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /x64-virtualmachine/handler_add.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // X86 4 | #include "instruction.hpp" 5 | 6 | // VM 7 | #include "virtual_machine.hpp" 8 | 9 | namespace vm::handler::add 10 | { 11 | namespace impl 12 | { 13 | template 14 | void handle_flags(virtual_machine* vm, T value, T previous_value, T addition) 15 | { 16 | // ZERO FLAG 17 | vm->context().flags().zero = value == 0x000; 18 | 19 | // OVERFLOW 20 | vm->context().flags().overflow = 21 | numerical_helper::addition_overflows(value, addition); 22 | 23 | // CARRY 24 | vm->context().flags().carry = 25 | numerical_helper::is_signed(value) != numerical_helper::is_signed(previous_value); 26 | 27 | // SIGN 28 | vm->context().flags().sign = numerical_helper::is_signed(value) ? 1 : 0; 29 | 30 | // PARITY 31 | const auto set_bit_count = numerical_helper::least_significant_bits(value); 32 | vm->context().flags().parity = set_bit_count % 2 == 0; // EVEN NUMBER OF SET BITS 33 | } 34 | } 35 | 36 | void handle(virtual_machine* vm, x86::instruction& instr); 37 | } -------------------------------------------------------------------------------- /x64-virtualmachine/handler_add_byte.cpp: -------------------------------------------------------------------------------- 1 | // VM 2 | #include "handler_add_byte.hpp" 3 | 4 | // COMPILER 5 | #include "compiler_helper.hpp" 6 | 7 | void vm::handler::add::byte(virtual_machine* vm, x86::instruction& instr) 8 | { 9 | compiler::unreferenced_variable(vm); 10 | compiler::unreferenced_variable(instr); 11 | } 12 | -------------------------------------------------------------------------------- /x64-virtualmachine/handler_add_byte.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // X86 4 | #include "instruction.hpp" 5 | 6 | // VM 7 | #include "virtual_machine.hpp" 8 | 9 | namespace vm::handler::add 10 | { 11 | void byte(virtual_machine* vm, x86::instruction& instr); 12 | } -------------------------------------------------------------------------------- /x64-virtualmachine/handler_add_displaced_destination.cpp: -------------------------------------------------------------------------------- 1 | // VM 2 | #include "handler_add_displaced_destination.hpp" 3 | #include "handler_add.hpp" 4 | 5 | // HELPER 6 | #include "compiler_helper.hpp" 7 | #include "numerical_helper.hpp" 8 | 9 | #include "global.hpp" 10 | 11 | void vm::handler::add::displaced_destination(virtual_machine* vm, x86::instruction& instr) 12 | { 13 | std::uint64_t addition = 0; 14 | std::uint64_t offset = 0; 15 | bool deref = true; 16 | 17 | // PARSE INSTRUCTION MODIFIER 18 | auto modifier = instr.get_modifier(0); 19 | switch (modifier.mode) 20 | { 21 | case 0: 22 | // ADD [DEST], SRC 23 | vm::handler::add::impl::displaced_destination_zero(vm, modifier, instr, addition, deref); 24 | break; 25 | 26 | case 1: 27 | // ADD [DEST+8-bit], SRC 28 | vm::handler::add::impl::displaced_destination_one(vm, modifier, instr, addition, offset, deref); 29 | break; 30 | 31 | case 2: 32 | // ADD [DEST+32-bit], SRC 33 | vm::handler::add::impl::displaced_destination_two(vm, modifier, instr, addition, offset, deref); 34 | break; 35 | 36 | case 3: 37 | // ADD DEST, SRC 38 | vm::handler::add::impl::displaced_destination_three(vm, modifier, instr, addition, deref); 39 | break; 40 | } 41 | 42 | // GET DESTINATION SIZE 43 | auto size = x86::registr::size::qword; 44 | 45 | // 32-bit? 46 | if (!instr.get_modifier(0).wide) 47 | { 48 | // 16-bit OVERRIDE? 49 | size = instr.prefix().has(x86::prefix::OPERAND_SIZE_OVERRIDE) ? 50 | x86::registr::size::word : 51 | x86::registr::size::dword; 52 | } 53 | 54 | // DEREF? 55 | auto& source_reg = vm->context().get(modifier.source_register); 56 | if (deref) // DEREFERENCE RESULT? 57 | { 58 | // UPDATE DEREF'D VALUE 59 | auto address = source_reg.ptr + offset; 60 | 61 | switch (size) 62 | { 63 | case x86::registr::size::word: 64 | { 65 | const auto previous_value = vm->memory().read(address); 66 | const auto casted_addition = static_cast(addition); 67 | std::uint16_t value = previous_value + casted_addition; 68 | vm->memory().write(value, address); 69 | 70 | 71 | // SET FLAGS 72 | vm::handler::add::impl::handle_flags(vm, value, previous_value, casted_addition); 73 | 74 | break; 75 | } 76 | 77 | 78 | case x86::registr::size::dword: 79 | { 80 | // SAVE OLD VALUE AND CALCULATE NEW 81 | const auto previous_value = vm->memory().read(address); 82 | const auto casted_addition = static_cast(addition); 83 | std::uint32_t value = previous_value + casted_addition; 84 | 85 | // WRITE 86 | vm->memory().write(value, address); 87 | 88 | // SET FLAGS 89 | vm::handler::add::impl::handle_flags(vm, value, previous_value, casted_addition); 90 | 91 | break; 92 | } 93 | 94 | 95 | case x86::registr::size::qword: 96 | { 97 | // SAVE OLD VALUE AND CALCULATE NEW 98 | const auto previous_value = vm->memory().read(address); 99 | auto value = previous_value + addition; 100 | 101 | // WRITE 102 | vm->memory().write(value, address); 103 | 104 | // SET FLAGS 105 | vm::handler::add::impl::handle_flags(vm, value, previous_value, addition); 106 | break; 107 | } 108 | } 109 | 110 | } 111 | else 112 | { 113 | // UPDATE REGISTER VALUE 114 | switch (size) 115 | { 116 | case x86::registr::size::word: 117 | { 118 | const auto casted_addition = static_cast(addition); 119 | const auto previous_value = source_reg.word; 120 | source_reg.word += casted_addition; 121 | 122 | // SET FLAGS 123 | vm::handler::add::impl::handle_flags(vm, 124 | source_reg.word, 125 | previous_value, 126 | casted_addition); 127 | 128 | break; 129 | } 130 | 131 | case x86::registr::size::dword: 132 | { 133 | const auto casted_addition = static_cast(addition); 134 | const auto previous_value = source_reg.dword; 135 | source_reg.dword += static_cast(addition); 136 | 137 | // SET FLAGS 138 | vm::handler::add::impl::handle_flags(vm, 139 | source_reg.dword, 140 | previous_value, 141 | casted_addition); 142 | break; 143 | } 144 | 145 | case x86::registr::size::qword: 146 | { 147 | const auto previous_value = source_reg.qword; 148 | source_reg.qword += addition; 149 | 150 | // SET FLAGS 151 | vm::handler::add::impl::handle_flags(vm, 152 | source_reg.qword, 153 | previous_value, 154 | addition); 155 | break; 156 | } 157 | } 158 | } 159 | } 160 | 161 | void vm::handler::add::impl::displaced_destination_zero( 162 | virtual_machine* vm [[maybe_unused]], 163 | x86::instruction::modifier_data_t& modifier [[maybe_unused]], 164 | x86::instruction& instr, 165 | uint64_t& addition, 166 | bool& derefence [[maybe_unused]]) 167 | { 168 | const auto operand = instr.operand().get(1); 169 | 170 | // GET DESTINATION SIZE 171 | auto size = x86::registr::size::qword; 172 | 173 | // 32-bit? 174 | if (!instr.get_modifier(0).wide) 175 | { 176 | // 16-bit OVERRIDE? 177 | size = instr.prefix().has(x86::prefix::OPERAND_SIZE_OVERRIDE) ? 178 | x86::registr::size::word : 179 | x86::registr::size::dword; 180 | } 181 | 182 | const auto dest_reg_name_container = x86::registr::names[modifier.destination_register]; 183 | const auto dest_reg_name = dest_reg_name_container[size].c_str(); 184 | 185 | global::console.log_raw("[O] ADD [{}], {}\n", dest_reg_name, operand); 186 | 187 | addition = operand; 188 | } 189 | 190 | void vm::handler::add::impl::displaced_destination_one( 191 | virtual_machine* vm [[maybe_unused]], 192 | x86::instruction::modifier_data_t& modifier [[maybe_unused]], 193 | x86::instruction& instr, 194 | uint64_t& addition, 195 | uint64_t& offset, 196 | bool& derefence [[maybe_unused]]) 197 | { 198 | // REVERSE ORDER UNPACK FOR SOME REASON 199 | const auto[operand, displacement] = instr.operand().get_multiple(1); 200 | 201 | 202 | offset = displacement; 203 | addition = operand; 204 | } 205 | 206 | void vm::handler::add::impl::displaced_destination_two( 207 | virtual_machine* vm[[maybe_unused]], 208 | x86::instruction::modifier_data_t& modifier, 209 | x86::instruction& instr, 210 | uint64_t& addition, 211 | uint64_t& offset, 212 | bool& derefence[[maybe_unused]]) 213 | { 214 | // REVERSE ORDER UNPACK FOR SOME REASON 215 | const auto[operand, displacement] = instr.operand().get_multiple(1); 216 | 217 | // GET DESTINATION SIZE 218 | auto size = x86::registr::size::qword; 219 | 220 | // 32-bit? 221 | if (!instr.get_modifier(0).wide) 222 | { 223 | // 16-bit OVERRIDE? 224 | size = instr.prefix().has(x86::prefix::OPERAND_SIZE_OVERRIDE) ? 225 | x86::registr::size::word : 226 | x86::registr::size::dword; 227 | } 228 | 229 | 230 | const auto dest_reg_name_container = x86::registr::names[modifier.destination_register]; 231 | const auto dest_reg_name = dest_reg_name_container[size].c_str(); 232 | 233 | global::console.log_raw("[O] ADD [{}+{:X}], {:X}\n", dest_reg_name, displacement, operand); 234 | 235 | offset = displacement; 236 | addition = operand; 237 | } 238 | 239 | void vm::handler::add::impl::displaced_destination_three( 240 | virtual_machine* vm[[maybe_unused]], 241 | x86::instruction::modifier_data_t& modifier, 242 | x86::instruction& instr, 243 | uint64_t& addition, 244 | bool& derefence) 245 | { 246 | const auto operand = instr.operand().get(1); 247 | 248 | // GET DESTINATION SIZE 249 | auto size = x86::registr::size::qword; 250 | 251 | // 32-bit? 252 | if (!instr.get_modifier(0).wide) 253 | { 254 | // 16-bit OVERRIDE? 255 | size = instr.prefix().has(x86::prefix::OPERAND_SIZE_OVERRIDE) ? 256 | x86::registr::size::word : 257 | x86::registr::size::dword; 258 | } 259 | 260 | const auto dest_reg_name_container = x86::registr::names[modifier.destination_register]; 261 | const auto dest_reg_name = dest_reg_name_container[size].c_str(); 262 | 263 | global::console.log_raw("[O] ADD {}, {:X}\n", dest_reg_name, operand); 264 | 265 | derefence = false; 266 | addition = operand; 267 | } 268 | -------------------------------------------------------------------------------- /x64-virtualmachine/handler_add_displaced_destination.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // X86 4 | #include "instruction.hpp" 5 | 6 | // VM 7 | #include "virtual_machine.hpp" 8 | 9 | namespace vm::handler::add 10 | { 11 | namespace impl 12 | { 13 | void displaced_destination_zero( 14 | virtual_machine* vm, 15 | x86::instruction::modifier_data_t& modifier, 16 | x86::instruction& instr, 17 | uint64_t& addition, 18 | bool& derefence); 19 | 20 | void displaced_destination_one( 21 | virtual_machine* vm, 22 | x86::instruction::modifier_data_t& modifier, 23 | x86::instruction& instr, 24 | uint64_t& addition, 25 | uint64_t& offset, 26 | bool& derefence); 27 | 28 | void displaced_destination_two( 29 | virtual_machine* vm, 30 | x86::instruction::modifier_data_t& modifier, 31 | x86::instruction& instr, 32 | uint64_t& addition, 33 | uint64_t& offset, 34 | bool& derefence); 35 | 36 | void displaced_destination_three( 37 | virtual_machine* vm, 38 | x86::instruction::modifier_data_t& modifier, 39 | x86::instruction& instr, 40 | uint64_t& addition, 41 | bool& derefence); 42 | } 43 | 44 | void displaced_destination(virtual_machine* vm, x86::instruction& instr); 45 | } -------------------------------------------------------------------------------- /x64-virtualmachine/handler_add_displaced_source.cpp: -------------------------------------------------------------------------------- 1 | // VM 2 | #include "handler_add_displaced_source.hpp" 3 | #include "handler_add.hpp" 4 | 5 | // HELPER 6 | #include "compiler_helper.hpp" 7 | #include "numerical_helper.hpp" 8 | #include "global.hpp" 9 | 10 | void vm::handler::add::impl::displaced_source_zero( 11 | virtual_machine* vm, 12 | x86::instruction::modifier_data_t& modifier, 13 | x86::instruction& instr, 14 | uint64_t& addition) 15 | { 16 | auto dest_size = x86::registr::size::qword; 17 | auto source_size = x86::registr::size::qword; 18 | 19 | auto& source_reg = vm->context().get(modifier.source_register); 20 | if (modifier.wide) 21 | { 22 | // PREFIX 67 FORCES 32-bit SOURCE 23 | if (instr.prefix().has(x86::prefix::ADDRESS_SIZE_OVERRIDE)) 24 | { 25 | addition = vm->memory().read(source_reg.dword_ptr()); 26 | source_size = x86::registr::size::dword; 27 | } 28 | else 29 | { 30 | 31 | addition = vm->memory().read(source_reg.ptr); 32 | } 33 | } 34 | else 35 | { 36 | // PREFIX 66 FORCES 16-bit SOURCE AND DESTINATION 37 | if (instr.prefix().has(x86::prefix::OPERAND_SIZE_OVERRIDE)) 38 | { 39 | addition = vm->memory().read(source_reg.word_ptr()); 40 | source_size = x86::registr::size::word; 41 | dest_size = x86::registr::size::word; 42 | } 43 | else 44 | { 45 | addition = vm->memory().read(source_reg.dword_ptr()); 46 | source_size = x86::registr::size::dword; 47 | dest_size = x86::registr::size::dword; 48 | } 49 | } 50 | 51 | // PRINT OPERATION 52 | const auto dest_reg_name_container = x86::registr::names[modifier.destination_register]; 53 | const auto dest_reg_name = dest_reg_name_container[dest_size].c_str(); 54 | 55 | const auto source_reg_name_container = x86::registr::names[modifier.source_register]; 56 | const auto source_reg_name = source_reg_name_container[source_size].c_str(); 57 | 58 | global::console.log_raw("[O] ADD %s, [%s]", dest_reg_name, source_reg_name); 59 | } 60 | 61 | void vm::handler::add::impl::displaced_source_one(virtual_machine* vm, 62 | x86::instruction::modifier_data_t& modifier, 63 | x86::instruction& instr, 64 | uint64_t& addition) 65 | { 66 | const auto displacement = instr.operand().get(1); 67 | 68 | auto dest_size = x86::registr::size::qword; 69 | auto source_size = x86::registr::size::qword; 70 | 71 | auto& source_reg = vm->context().get(modifier.source_register); 72 | if (modifier.wide) 73 | { 74 | // PREFIX 67 FORCES 32-bit SOURCE 75 | if (instr.prefix().has(x86::prefix::ADDRESS_SIZE_OVERRIDE)) 76 | { 77 | addition = vm->memory().read(source_reg.dword_ptr() + displacement); 78 | source_size = x86::registr::size::dword; 79 | } 80 | else 81 | { 82 | 83 | addition = vm->memory().read(source_reg.ptr + displacement); 84 | } 85 | } 86 | else 87 | { 88 | // PREFIX 66 FORCES 16-bit SOURCE AND DESTINATION 89 | if (instr.prefix().has(x86::prefix::OPERAND_SIZE_OVERRIDE)) 90 | { 91 | addition = vm->memory().read(source_reg.word_ptr() + displacement); 92 | source_size = x86::registr::size::word; 93 | dest_size = x86::registr::size::word; 94 | } 95 | else 96 | { 97 | addition = vm->memory().read(source_reg.dword_ptr() + displacement); 98 | source_size = x86::registr::size::dword; 99 | dest_size = x86::registr::size::dword; 100 | } 101 | } 102 | 103 | // PRINT OPERATION 104 | const auto dest_reg_name_container = x86::registr::names[modifier.destination_register]; 105 | const auto dest_reg_name = dest_reg_name_container[dest_size].c_str(); 106 | 107 | const auto source_reg_name_container = x86::registr::names[modifier.source_register]; 108 | const auto source_reg_name = source_reg_name_container[source_size].c_str(); 109 | 110 | global::console.log_raw("[O] ADD %s, [%s+%02X]\n", dest_reg_name, source_reg_name, displacement); 111 | } 112 | 113 | void vm::handler::add::impl::displaced_source_two( 114 | virtual_machine* vm, 115 | x86::instruction::modifier_data_t& modifier, 116 | x86::instruction& instr, 117 | uint64_t& addition) 118 | { 119 | const auto displacement = instr.operand().get(1); 120 | 121 | auto dest_size = x86::registr::size::qword; 122 | auto source_size = x86::registr::size::qword; 123 | 124 | auto& source_reg = vm->context().get(modifier.source_register); 125 | if (modifier.wide) 126 | { 127 | // PREFIX 67 FORCES 32-bit SOURCE 128 | if (instr.prefix().has(x86::prefix::ADDRESS_SIZE_OVERRIDE)) 129 | { 130 | addition = vm->memory().read(source_reg.dword_ptr() + displacement); 131 | source_size = x86::registr::size::dword; 132 | } 133 | else 134 | { 135 | 136 | addition = vm->memory().read(source_reg.ptr + displacement); 137 | } 138 | } 139 | else 140 | { 141 | // PREFIX 66 FORCES 16-bit SOURCE AND DESTINATION 142 | if (instr.prefix().has(x86::prefix::OPERAND_SIZE_OVERRIDE)) 143 | { 144 | addition = vm->memory().read(source_reg.word_ptr() + displacement); 145 | source_size = x86::registr::size::word; 146 | dest_size = x86::registr::size::word; 147 | } 148 | else 149 | { 150 | addition = vm->memory().read(source_reg.dword_ptr() + displacement); 151 | source_size = x86::registr::size::dword; 152 | dest_size = x86::registr::size::dword; 153 | } 154 | } 155 | 156 | // PRINT OPERATION 157 | 158 | const auto dest_reg_name_container = x86::registr::names[modifier.destination_register]; 159 | const auto dest_reg_name = dest_reg_name_container[dest_size].c_str(); 160 | 161 | const auto source_reg_name_container = x86::registr::names[modifier.source_register]; 162 | const auto source_reg_name = source_reg_name_container[source_size].c_str(); 163 | 164 | global::console.log_raw("[O] ADD %s, [%s+%08lX]\n", dest_reg_name, source_reg_name, displacement); 165 | } 166 | 167 | void vm::handler::add::impl::displaced_source_three( 168 | virtual_machine* vm, 169 | x86::instruction::modifier_data_t& modifier, 170 | x86::instruction& instr, 171 | uint64_t& addition) 172 | { 173 | auto dest_size = x86::registr::size::qword; 174 | auto source_size = x86::registr::size::qword; 175 | 176 | auto& source_reg = vm->context().get(modifier.source_register); 177 | if (modifier.wide) 178 | { 179 | // PREFIX 67 FORCES 32-bit SOURCE 180 | if (instr.prefix().has(x86::prefix::ADDRESS_SIZE_OVERRIDE)) 181 | { 182 | addition = source_reg.dword; 183 | source_size = x86::registr::size::dword; 184 | } 185 | else 186 | { 187 | 188 | addition = source_reg.qword; 189 | } 190 | } 191 | else 192 | { 193 | // PREFIX 66 FORCES 16-bit SOURCE AND DESTINATION 194 | if (instr.prefix().has(x86::prefix::OPERAND_SIZE_OVERRIDE)) 195 | { 196 | addition = source_reg.word; 197 | source_size = x86::registr::size::word; 198 | dest_size = x86::registr::size::word; 199 | } 200 | else 201 | { 202 | addition = source_reg.dword; 203 | source_size = x86::registr::size::dword; 204 | dest_size = x86::registr::size::dword; 205 | } 206 | } 207 | 208 | // PRINT OPERATION 209 | 210 | const auto dest_reg_name_container = x86::registr::names[modifier.destination_register]; 211 | const auto dest_reg_name = dest_reg_name_container[dest_size].c_str(); 212 | 213 | const auto source_reg_name_container = x86::registr::names[modifier.source_register]; 214 | const auto source_reg_name = source_reg_name_container[source_size].c_str(); 215 | 216 | global::console.log_raw("[O] ADD %s, %s\n", dest_reg_name, source_reg_name); 217 | } 218 | 219 | void vm::handler::add::displaced_source(virtual_machine* vm, x86::instruction& instr) 220 | { 221 | // READ MODRM OPERAND AT FIRST BYTE 222 | auto modifier = instr.get_modifier(0); 223 | 224 | std::uint64_t addition = 0; 225 | switch (modifier.mode) 226 | { 227 | case 0: 228 | // ADD DEST, [SRC] 229 | vm::handler::add::impl::displaced_source_zero(vm, modifier, instr, addition); 230 | break; 231 | 232 | case 1: 233 | // ADD DEST, [SRC+8-bit] 234 | vm::handler::add::impl::displaced_source_one(vm, modifier, instr, addition); 235 | break; 236 | 237 | case 2: 238 | // ADD DEST, [SRC+32-bit] 239 | vm::handler::add::impl::displaced_source_two(vm, modifier, instr, addition); 240 | break; 241 | 242 | case 3: 243 | // ADD DEST, SRC 244 | vm::handler::add::impl::displaced_source_three(vm, modifier, instr, addition); 245 | break; 246 | } 247 | 248 | 249 | // TODO, HANDLE LOCK PREFIX? NECESSARY? 250 | // auto lock_operand = instr.prefix().has(x86::prefix::LOCK); 251 | 252 | /* 253 | PREFIX PSEUDO: 254 | 255 | IF REX.W 256 | IGNORE PREFIX-66 257 | 258 | DESTINATION_REG = 64-bit 259 | 260 | IF PREFIX67 261 | SOURCE_REG = 32-bit 262 | ELSE 263 | SOURCE-REG = 64-bit 264 | 265 | 266 | ELSE 267 | IGNORE PREFIX-67 268 | 269 | IF PREFIX-66 270 | DESTINATION_REG = 16-bit 271 | SOURCE_REG = 16-bit 272 | ELSE 273 | DESTINATION_REG = 32-bit 274 | SOURCE_REG = 32-bit 275 | */ 276 | 277 | auto& destination_reg = vm->context().get(modifier.destination_register); 278 | if (modifier.wide) 279 | { 280 | // SAVE OLD VALUE 281 | const auto previous_value = destination_reg.qword; 282 | 283 | // IF 67 IS SET, ADDITION WILL BE READ (BY THE HANDLERS) AS 32-bit 284 | destination_reg.qword += addition; 285 | 286 | // SET FLAGS 287 | vm::handler::add::impl::handle_flags( 288 | vm, 289 | destination_reg.qword, 290 | previous_value, 291 | addition); 292 | } 293 | else 294 | { 295 | // PREFIX 66 OVERRIDES PREFIX 67 296 | if (instr.prefix().has(x86::prefix::OPERAND_SIZE_OVERRIDE)) 297 | { 298 | // IF 66 IS SET, ADDITION WILL BE READ (BY THE HANDLERS) AS 16-bit 299 | 300 | // SAVE OLD VALUE 301 | const auto previous_value = destination_reg.word; 302 | 303 | // ADD VALUE 304 | const auto casted_addition = static_cast(addition); 305 | destination_reg.word += casted_addition; 306 | 307 | // SET FLAGS 308 | vm::handler::add::impl::handle_flags( 309 | vm, 310 | destination_reg.word, 311 | previous_value, 312 | casted_addition); 313 | 314 | } 315 | else // NO PREFIX, WRITE DWORD 316 | { 317 | // SAVE OLD VALUE 318 | const auto previous_value = destination_reg.dword; 319 | 320 | // ADD VALUE 321 | const auto casted_addition = static_cast(addition); 322 | destination_reg.dword += casted_addition; 323 | 324 | // SET FLAGS 325 | vm::handler::add::impl::handle_flags( 326 | vm, 327 | destination_reg.dword, 328 | previous_value, 329 | casted_addition); 330 | } 331 | } 332 | } 333 | -------------------------------------------------------------------------------- /x64-virtualmachine/handler_add_displaced_source.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // X86 4 | #include "instruction.hpp" 5 | 6 | // VM 7 | #include "virtual_machine.hpp" 8 | 9 | namespace vm::handler::add 10 | { 11 | namespace impl 12 | { 13 | void displaced_source_zero( 14 | virtual_machine* vm, 15 | x86::instruction::modifier_data_t& modifier, 16 | x86::instruction& instr, 17 | uint64_t& addition); 18 | 19 | void displaced_source_one( 20 | virtual_machine* vm, 21 | x86::instruction::modifier_data_t& modifier, 22 | x86::instruction& instr, 23 | uint64_t& addition); 24 | 25 | void displaced_source_two( 26 | virtual_machine* vm, 27 | x86::instruction::modifier_data_t& modifier, 28 | x86::instruction& instr, 29 | uint64_t& addition); 30 | 31 | void displaced_source_three( 32 | virtual_machine* vm, 33 | x86::instruction::modifier_data_t& modifier, 34 | x86::instruction& instr, 35 | uint64_t& addition); 36 | } 37 | void displaced_source(virtual_machine* vm, x86::instruction& instr); 38 | } -------------------------------------------------------------------------------- /x64-virtualmachine/handler_unknown.cpp: -------------------------------------------------------------------------------- 1 | #include "handler_unknown.hpp" 2 | 3 | void vm::handler::unknown(x86::instruction& instr) 4 | { 5 | // PRINT SIZE 6 | printf("Size: [%02X] ", instr.size()); 7 | 8 | // PRINT PREFIX 9 | printf("Prefix: ["); 10 | for (const auto prefix : instr.prefix()) 11 | printf("%2X", prefix); 12 | printf("] "); 13 | 14 | // PRINT REX 15 | if (instr.rex().has_value()) 16 | { 17 | auto rex_value = instr.rex().value(); 18 | printf("REX: %s ", rex_value.to_string().c_str()); 19 | } 20 | 21 | // PRINT OPCODE 22 | printf("Opcode: ["); 23 | for (const auto& opcode : instr.opcode().buffer()) 24 | printf("%02X", opcode); 25 | printf("] "); 26 | 27 | // PRINT OPERAND 28 | printf("Operand: ["); 29 | for (const auto& operand : instr.operand().buffer()) 30 | printf("%02X", operand); 31 | printf("]"); 32 | } 33 | -------------------------------------------------------------------------------- /x64-virtualmachine/handler_unknown.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // X86 4 | #include "instruction.hpp" 5 | 6 | namespace vm::handler 7 | { 8 | void unknown(x86::instruction& instr); 9 | } -------------------------------------------------------------------------------- /x64-virtualmachine/handlers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // VM 4 | #include "handler_add.hpp" 5 | #include "handler_unknown.hpp" -------------------------------------------------------------------------------- /x64-virtualmachine/instruction.cpp: -------------------------------------------------------------------------------- 1 | // X86 2 | #include "instruction.hpp" 3 | #include "instruction_rex.hpp" 4 | #include "instruction_prefix.hpp" 5 | #include "instruction_operand.hpp" 6 | #include "instruction_modrm.hpp" 7 | 8 | bool& x86::instruction::opcode_initialised() 9 | { 10 | return this->m_opcode_init; 11 | } 12 | 13 | bool& x86::instruction::operand_initialised() 14 | { 15 | return this->m_operand_init; 16 | } 17 | 18 | bool& x86::instruction::prefix_initialised() 19 | { 20 | return this->m_prefix_init; 21 | } 22 | 23 | bool& x86::instruction::rex_initialised() 24 | { 25 | return this->m_rex_init; 26 | } 27 | 28 | std::uint8_t& x86::instruction::size() 29 | { 30 | return this->m_size; 31 | } 32 | 33 | std::string x86::instruction::name() 34 | { 35 | return x86::opcode::names.at(this->opcode().as()); 36 | } 37 | 38 | x86::opcode& x86::instruction::opcode() 39 | { 40 | return this->m_opcode; 41 | } 42 | 43 | x86::operand& x86::instruction::operand() 44 | { 45 | return this->m_operand; 46 | } 47 | 48 | x86::prefix& x86::instruction::prefix() 49 | { 50 | return this->m_prefix; 51 | } 52 | 53 | std::optional& x86::instruction::rex() 54 | { 55 | return this->m_rex; 56 | } 57 | 58 | x86::instruction::modifier_data_t x86::instruction::get_modifier(size_t index) 59 | { 60 | auto modrm = this->operand().get(index); 61 | 62 | auto mode = modrm.mode; 63 | auto destination_reg = modrm.reg; 64 | auto source_reg = modrm.rm; 65 | std::uint8_t wide = 0; 66 | 67 | // HANDLE REX PREFIX IF REX IS SET AND OPERAND OVERRIDE IS SET 68 | if (this->rex().has_value() && this->rex().value().w == 1) 69 | { 70 | // EXTENSION OF MODR/M 71 | auto extended_modrm = x86::modrm_e(modrm, this->rex().value()); 72 | 73 | // SAVE EXTENDED VALUES 74 | destination_reg = extended_modrm.reg; 75 | source_reg = extended_modrm.rm; 76 | wide = this->rex().value().w; 77 | } 78 | 79 | return x86::instruction::modifier_data_t{ mode, wide, source_reg, destination_reg }; 80 | } 81 | -------------------------------------------------------------------------------- /x64-virtualmachine/instruction.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | #include 6 | #include 7 | 8 | // x86 9 | #include "instruction_opcode.hpp" 10 | #include "instruction_rex.hpp" 11 | #include "instruction_operand.hpp" 12 | #include "instruction_prefix.hpp" 13 | 14 | namespace x86 15 | { 16 | // BASE INSTRUCTION CLASS 17 | class instruction 18 | { 19 | public: 20 | // INIT CHECKS 21 | bool& opcode_initialised(); 22 | bool& operand_initialised(); 23 | bool& prefix_initialised(); 24 | bool& rex_initialised(); 25 | 26 | // INFORMATION 27 | std::uint8_t& size(); // INSTRUCTION SIZE 28 | std::string name(); // OPCODE NAME 29 | x86::opcode& opcode(); // OPCODE VALUE 30 | x86::operand& operand(); // OPERAND VALUE 31 | x86::prefix& prefix(); // PREFIX VALUE 32 | std::optional& rex(); // REX VALUE 33 | 34 | // RETURNS MODRM DATA EXTENDED WITH POSSIBLE REX PREFIX, AND REX DATA 35 | struct modifier_data_t 36 | { 37 | std::uint8_t mode; 38 | std::uint8_t wide; 39 | std::uint8_t source_register; 40 | std::uint8_t destination_register; 41 | }; 42 | modifier_data_t get_modifier(size_t index); 43 | 44 | private: 45 | bool m_opcode_init; 46 | bool m_operand_init; 47 | bool m_prefix_init; 48 | bool m_rex_init; 49 | 50 | std::uint8_t m_size; 51 | 52 | x86::opcode m_opcode; // 1-3 BYTES 53 | x86::operand m_operand; // 0-8 BYTES 54 | x86::prefix m_prefix; // 0-4 BYTES 55 | std::optional m_rex; // 0-1 BYTES 56 | }; 57 | } -------------------------------------------------------------------------------- /x64-virtualmachine/instruction_modrm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | 6 | namespace x86 7 | { 8 | // REGISTER OPERAND 9 | struct modrm 10 | { 11 | std::uint8_t rm : 3; // SOURCE REGISTER ID 12 | std::uint8_t reg : 3; // DESTINATION REGISTER ID 13 | std::uint8_t mode : 2; // ADDRESSING MODE 14 | 15 | // FOUR DIFFERENT MODES EXIST (WITH EXCEPTIONS): 16 | // MODE 0: [REG] 17 | // MODE 1: [REG]+disp8 18 | // MODE 2: [REG]+disp32 19 | // MODE 3: REG 20 | 21 | // CALCULATE OPERAND SIZE FROM DATA MODE 22 | std::uint8_t data_size() 23 | { 24 | switch (this->mode) 25 | { 26 | // 8-bit DISPLACEMENT 27 | case 1: 28 | { 29 | return 1; 30 | } 31 | // 32-bit DISPLACEMENT 32 | case 2: 33 | { 34 | return 4; 35 | } 36 | // NO DISPLACEMENT 37 | default: 38 | return 0; 39 | } 40 | } 41 | 42 | // GET DATA MODE AS STRING 43 | std::string mode_to_string() 44 | { 45 | const char* modes[] = { 46 | "Dereference", 47 | "8-bit displacement", 48 | "32-bit displacement", 49 | "No displacement" 50 | }; 51 | 52 | if (this->mode > 3) 53 | throw std::exception("Invalid modrm mode"); 54 | 55 | return std::string( modes[this->mode] ); 56 | } 57 | }; 58 | 59 | // EXTENDED REGISTER OPERAND 60 | struct modrm_e 61 | { 62 | modrm_e() {} 63 | 64 | modrm_e(x86::modrm operand, x86::rex rex) 65 | { 66 | this->rm = operand.rm | (rex.b << 3); 67 | this->reg = operand.reg | (rex.r << 3); 68 | this->mode = operand.mode; 69 | } 70 | 71 | std::uint8_t rm : 4; 72 | std::uint8_t reg : 4; 73 | std::uint8_t mode : 2; 74 | }; 75 | } -------------------------------------------------------------------------------- /x64-virtualmachine/instruction_opcode.cpp: -------------------------------------------------------------------------------- 1 | #include "instruction_opcode.hpp" 2 | 3 | // NAMES 4 | const x86::opcode::name_map_t x86::opcode::names = 5 | { 6 | // ADD 7 | { x86::opcode::add_byte, "ADD" }, 8 | { x86::opcode::add_reg, "ADD" }, 9 | { x86::opcode::add_displaced_byte, "ADD" }, 10 | { x86::opcode::add_displaced_source, "ADD" }, 11 | { x86::opcode::add_al, "ADD" }, 12 | { x86::opcode::add_rax, "ADD" }, 13 | { x86::opcode::add_wide, "ADD" }, 14 | { x86::opcode::add_displaced_destination, "ADD" }, 15 | { x86::opcode::add_byte_extended, "ADD" } 16 | 17 | }; 18 | 19 | std::vector& x86::opcode::buffer() 20 | { 21 | return this->m_opcode; 22 | } 23 | -------------------------------------------------------------------------------- /x64-virtualmachine/instruction_opcode.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | namespace x86 10 | { 11 | class opcode 12 | { 13 | public: 14 | // FROM VECTOR 15 | opcode(std::vector opcode) : m_opcode(opcode) {} 16 | 17 | // FROM COMPILER CONSTANT ARRAY 18 | template 19 | opcode(T(&opcode)[N]) : m_opcode(opcode) {} 20 | 21 | // DEFAULT CTOR 22 | opcode() : m_opcode() {} 23 | 24 | // BUFFER 25 | std::vector& buffer(); 26 | 27 | // READ AS 'T', SANITY CHECKED 28 | template 29 | T as() 30 | { 31 | const auto size = this->buffer().size(); 32 | 33 | // HANDLE WHEN CALLING WITH BIGGER INTEGER SIZE THAN BUFFER CAPACITY 34 | if (sizeof(T) > size) 35 | { 36 | // ASSUME INTEGER, BAD PRACTICE 37 | // NEED TO USE STD::ENABLE_IF FOR THIS 38 | T value{}; 39 | 40 | for (size_t i = 0; i < size; i++) 41 | value += this->buffer().at(i) << (8 * i); 42 | 43 | return value; 44 | } 45 | 46 | return *reinterpret_cast(this->buffer().data()); 47 | } 48 | 49 | #pragma region Opcodes 50 | #pragma region ADD 51 | /* 52 | NAME: ADD 53 | DESCRIPTION: { 54 | The ADD instruction performs integer addition. 55 | It evaluates the result for both signed and unsigned integer operands 56 | and sets the CF and OF flags to indicate a carry (overflow) 57 | in the signed or unsigned result, respectively. The SF flag 58 | indicates the sign of the signed result. 59 | } 60 | 61 | */ 62 | constexpr static std::uint32_t add_byte = 0x00; 63 | constexpr static std::uint32_t add_reg = 0x01; 64 | constexpr static std::uint32_t add_displaced_byte = 0x02; 65 | constexpr static std::uint32_t add_displaced_source = 0x03; // DONE? MISSING PREFIX SUPPORT (66 AND LOCK) AND FLAGS 66 | constexpr static std::uint32_t add_al = 0x04; 67 | constexpr static std::uint32_t add_rax = 0x05; 68 | constexpr static std::uint32_t add_wide = 0x80; 69 | constexpr static std::uint32_t add_displaced_destination = 0x81; // DONE? MISSING PREFIX SUPPORT (66 NEEDS TO BE TESTED) AND FLAGS 70 | constexpr static std::uint32_t add_byte_extended = 0x83; 71 | #pragma endregion 72 | // INC 73 | // DEC 74 | // SUB 75 | // DIV 76 | // MUL 77 | // POP 78 | // PUSH 79 | // JMP 80 | // CALL 81 | // RET 82 | // MOV 83 | #pragma endregion 84 | 85 | // STATIC OPCODE NAME LIST 86 | using name_map_t = std::map; 87 | const static name_map_t names; 88 | 89 | private: 90 | // RAW OPCODE DATA 91 | std::vector m_opcode; 92 | 93 | }; 94 | } -------------------------------------------------------------------------------- /x64-virtualmachine/instruction_operand.cpp: -------------------------------------------------------------------------------- 1 | #include "instruction_operand.hpp" 2 | 3 | const x86::operand::operand_map_t x86::operand::info = 4 | { 5 | // ADD 6 | { x86::opcode::add_displaced_source, { true, 1/*ModRM*/ } }, 7 | { x86::opcode::add_displaced_destination, { true, 1/*ModRM*/ + 4/*DATA*/ } } 8 | 9 | }; 10 | 11 | std::vector& x86::operand::buffer() 12 | { 13 | return this->m_operand; 14 | } 15 | -------------------------------------------------------------------------------- /x64-virtualmachine/instruction_operand.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | #include 6 | #include 7 | 8 | // x86 9 | #include "instruction_opcode.hpp" 10 | 11 | namespace x86 12 | { 13 | class operand 14 | { 15 | public: 16 | // FROM VECTOR 17 | operand(std::vector operand) : m_operand(operand) {} 18 | 19 | // FROM COMPILER CONSTANT ARRAY 20 | template 21 | operand(T(&operand)[N]) : m_operand(operand) {} 22 | 23 | // DEFAULT CTOR 24 | operand() : m_operand() {} 25 | 26 | // OPERAND BUFFER 27 | std::vector& buffer(); 28 | 29 | // READ AS 'T' AT INDEX 'index', SANITY CHECKED 30 | template 31 | T get(size_t index) 32 | { 33 | if (index + sizeof(T) > this->buffer().size()) 34 | { 35 | throw std::exception("Operand size mismatch"); 36 | } 37 | 38 | return *reinterpret_cast(this->buffer().data() + index); 39 | } 40 | 41 | private: 42 | // READ AS 'T' AT INDEX 'index', SANITY CHECKED AND INDEX GET'S UPDATED DYNAMICALLY 43 | template 44 | T get_dynamic(size_t& index) 45 | { 46 | const T value = get(index); 47 | index += sizeof(T); 48 | return value; 49 | } 50 | public: 51 | // READ MULTIPLE OPERANDS IN MEMORY ORDER, UNPACK IN REVERSE 52 | template 53 | std::tuple get_multiple(size_t index) 54 | { 55 | return std::make_tuple(get_dynamic(index)...); 56 | } 57 | 58 | // OPERAND INFORMATION 59 | // CONTAINS SIZE AND IF MODRM EXISTS 60 | struct operand_info 61 | { 62 | //operand_info(bool new_modrm, std::uint8_t new_size) : modrm(new_modrm), size(new_size) {} 63 | bool modrm; 64 | std::uint8_t size; 65 | }; 66 | 67 | // STATIC OPERAND INFO TABLE 68 | using operand_map_t = std::map; 69 | const static operand_map_t info; 70 | 71 | private: 72 | std::vector m_operand; 73 | }; 74 | } -------------------------------------------------------------------------------- /x64-virtualmachine/instruction_prefix.cpp: -------------------------------------------------------------------------------- 1 | // X86 2 | #include "instruction_prefix.hpp" 3 | 4 | const x86::prefix::prefix_list_t x86::prefix::list = { 5 | x86::prefix::id::LOCK, 6 | x86::prefix::id::REPNE, 7 | x86::prefix::id::REP, 8 | x86::prefix::id::BOUND, 9 | x86::prefix::id::CS_OVERRIDE, 10 | x86::prefix::id::SS_OVERRIDE, 11 | x86::prefix::id::DS_OVERRIDE, 12 | x86::prefix::id::ES_OVERRIDE, 13 | x86::prefix::id::FS_OVERRIDE, 14 | x86::prefix::id::GS_OVERRIDE, 15 | x86::prefix::id::BR_NOT_TAKEN, 16 | x86::prefix::id::BR_TAKEN, 17 | x86::prefix::id::OPERAND_SIZE_OVERRIDE, 18 | x86::prefix::id::ADDRESS_SIZE_OVERRIDE, 19 | }; 20 | 21 | bool x86::prefix::has(std::uint8_t prefix) 22 | { 23 | return std::any_of( 24 | this->buffer().begin(), this->buffer().end(), 25 | [prefix](std::uint8_t iter_prefix) { 26 | return iter_prefix == prefix; 27 | }); 28 | } 29 | 30 | bool x86::prefix::is(std::uint8_t prefix) 31 | { 32 | return std::any_of( 33 | x86::prefix::list.begin(), x86::prefix::list.end(), 34 | [prefix](std::uint8_t iter_prefix) { 35 | return iter_prefix == prefix; 36 | }); 37 | } 38 | 39 | void x86::prefix::append(std::uint8_t prefix) 40 | { 41 | this->buffer().emplace_back(prefix); 42 | } 43 | ; 44 | x86::prefix::vector_iter_t x86::prefix::begin() 45 | { 46 | return this->buffer().begin(); 47 | } 48 | 49 | x86::prefix::vector_iter_t x86::prefix::end() 50 | { 51 | return this->buffer().end(); 52 | } 53 | 54 | std::vector& x86::prefix::buffer() 55 | { 56 | return this->m_buffer; 57 | } 58 | -------------------------------------------------------------------------------- /x64-virtualmachine/instruction_prefix.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | #include 6 | 7 | namespace x86 8 | { 9 | class prefix 10 | { 11 | public: 12 | prefix() : m_buffer() {} 13 | 14 | // INFORMATION 15 | bool has(std::uint8_t prefix); 16 | 17 | // SETTERS 18 | void append(std::uint8_t prefix); 19 | 20 | // ITERATOR 21 | using vector_iter_t = std::vector::const_iterator; 22 | vector_iter_t begin(); 23 | vector_iter_t end(); 24 | 25 | // STATICS 26 | 27 | // IS BYTE A LEGACY PREFIX? 28 | static bool is(std::uint8_t prefix); 29 | 30 | // LIST OF PREFIXES 31 | using prefix_list_t = std::array; 32 | static const prefix_list_t list; 33 | 34 | // ID LIST OF LEGACY PREFIXES 35 | enum id 36 | { 37 | /* GROUP 1 */ 38 | LOCK = 0xF0, // FORCES PROCESSOR TO LOCK MEMORY 39 | REPNE = 0xF2, // CAUSES INSTRUCTION TO BE REPEATED TO EACH ELEMENT UNTIL NOT ZERO 40 | REP = 0xF3, // CAUSES INSTRUCTION TO BE REPEATED FOR EACH ELEMENT IN STRING/ARRAY 41 | BOUND = 0xF2, // ONLY WHEN IT'S ENABLED AND PRECEDES NEAR CALL/RET/JCC 42 | 43 | /* GROUP 2 */ 44 | 45 | // Use with branch instruction is reserved 46 | CS_OVERRIDE = 0x2E, 47 | SS_OVERRIDE = 0x36, 48 | DS_OVERRIDE = 0x3E, 49 | ES_OVERRIDE = 0x26, 50 | FS_OVERRIDE = 0x64, 51 | GS_OVERRIDE = 0x65, 52 | 53 | // ONLY WITH JCC 54 | BR_NOT_TAKEN = 0x2E, 55 | BR_TAKEN = 0x3E, 56 | 57 | /* GROUP 3 */ 58 | OPERAND_SIZE_OVERRIDE = 0x66, // SWITCH BETWEEN OPERAND SIZES (PREFIX FORCES NON-DEFAULT) 59 | 60 | /* GROUP 4 */ 61 | ADDRESS_SIZE_OVERRIDE = 0x67 // SWITCH BETWEEN ADDRESS SIZE (PREFIX FORCES NON-DEFAULT) 62 | }; 63 | 64 | private: 65 | // ACCESSORS 66 | std::vector& buffer(); 67 | 68 | // PRIVATE MEMBERS 69 | 70 | // PREFIX BUFFER 71 | // MAYBE USE BITMAP? 72 | std::vector m_buffer; 73 | }; 74 | 75 | 76 | }; -------------------------------------------------------------------------------- /x64-virtualmachine/instruction_rex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | #include 6 | 7 | namespace x86 8 | { 9 | // REX PREFIX STRUCTURE 10 | struct rex 11 | { 12 | std::uint8_t b : 1; // EXTENSION OF THE ModR/M 'r/m' FIELD, SIB 'base' FIELD, OR OPCODE 'reg' FIELD 13 | std::uint8_t x : 1; // EXTENSION OF SIB 'index' FIELD 14 | std::uint8_t r : 1; // EXTENSION OF ModR/M 'reg' FIELD 15 | std::uint8_t w : 1; // OPERAND SIZE OVERRIDE ( 1 = 64-bit OPERAND, 0 = CS.D OPERAND ) 16 | std::uint8_t id : 4; // 0100 IDENTIFIER 17 | 18 | std::string to_string() 19 | { 20 | std::string str{}; 21 | str.reserve(40); 22 | sprintf_s(str.data(), 40, "[B->%X, X->%X, R->%X, W->%X]", this->b, this->x, this->r, this->w); 23 | 24 | return str; 25 | } 26 | }; 27 | }; -------------------------------------------------------------------------------- /x64-virtualmachine/loggr.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "fmt/core.h" 6 | 7 | class loggr 8 | { 9 | public: 10 | loggr() 11 | { 12 | // SETUP CONSOLE IF NOT PRESENT 13 | auto console_window = GetConsoleWindow(); 14 | if (console_window == 0x00) 15 | { 16 | if (!AllocConsole()) 17 | { 18 | // ???? SHOULD NEVER HAPPEN 19 | return; 20 | } 21 | 22 | std::freopen("CONOUT$", "w", stdout); 23 | 24 | m_did_allocate_console = true; 25 | } 26 | } 27 | ~loggr() 28 | { 29 | // FREE CONSOLE IF DYNAMICALLY ALLOCATED 30 | if (m_did_allocate_console) 31 | { 32 | const auto freed = FreeConsole(); 33 | 34 | if (!freed) 35 | { 36 | // ?? 37 | } 38 | } 39 | } 40 | 41 | // CONSOLE LOGGING FUNCTIONS 42 | template 43 | inline void log_raw(T... arguments) const 44 | { 45 | fmt::print(arguments...); 46 | } 47 | 48 | inline void log(std::string_view message) const 49 | { 50 | fmt::print("[+] {}\n", message); 51 | } 52 | inline void log_error(std::string_view message) const 53 | { 54 | fmt::print("[!] {}\n", message); 55 | } 56 | 57 | template 58 | inline void log(std::string_view variable_name, const T& value) const 59 | { 60 | constexpr auto format_string = hex ? 61 | "[=] {:<15} {:X}\n" : 62 | "[=] {:<15} {}\n"; 63 | 64 | fmt::print(format_string, variable_name, value); 65 | } 66 | 67 | template 68 | inline void log_error_indented(std::string_view message) const 69 | { 70 | fmt::print("[!] {:<{}} {}\n", ' ', indentation, message); 71 | } 72 | 73 | template 74 | inline void log_indented(std::string_view message) const 75 | { 76 | fmt::print("[+] {:<{}} {}\n", ' ', indentation, message); 77 | } 78 | 79 | template 80 | inline void log_indented(std::string_view variable_name, const T& value) const 81 | { 82 | constexpr auto format_string = hex ? 83 | "[=] {:<{}} {:.<15} {:X}\n" : 84 | "[=] {:<{}} {:.<15} {}\n"; 85 | 86 | fmt::print(format_string, ' ', indentation, variable_name, value); 87 | } 88 | 89 | 90 | // CONSOLE MODIFICATION FUNCTIONS 91 | inline COORD get_position() const 92 | { 93 | CONSOLE_SCREEN_BUFFER_INFO info; 94 | if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info)) 95 | { 96 | this->log_error("Failed to get cursor position"); 97 | return { 0, 0 }; 98 | } 99 | 100 | return info.dwCursorPosition; 101 | } 102 | inline void set_position(const COORD cursor) const 103 | { 104 | if (!SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursor)) 105 | { 106 | this->log_error("Failed to set cursor position"); 107 | 108 | } 109 | } 110 | inline void clear_line() const 111 | { 112 | // GET CURSOR POSITION 113 | auto position = this->get_position(); 114 | 115 | 116 | position.X = 0; 117 | 118 | // CLEAR LINE 119 | DWORD count = 0; 120 | const auto handle = GetStdHandle(STD_OUTPUT_HANDLE); 121 | FillConsoleOutputCharacter(handle, ' ', 150, position, &count); 122 | 123 | // RESET POSITION 124 | set_position(position); 125 | } 126 | 127 | private: 128 | bool m_did_allocate_console = false; 129 | 130 | }; -------------------------------------------------------------------------------- /x64-virtualmachine/numerical_helper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace numerical_helper 4 | { 5 | template 6 | __forceinline constexpr T round_to_multiple(T number, T alignment) 7 | { 8 | const auto remainder = number % alignment; 9 | 10 | if (alignment == 0x00 || remainder == 0x00) 11 | return number; 12 | 13 | return number + alignment - remainder; 14 | } 15 | 16 | template 17 | __forceinline constexpr std::uint8_t least_significant_bits(T a) 18 | { 19 | auto byte = static_cast(a); 20 | 21 | std::uint8_t count = 0; 22 | for (size_t i = 0; i < 8; i++) 23 | { 24 | const auto bit = (byte >> i) & 0x01; 25 | if (bit == 0x01) 26 | ++count; 27 | } 28 | 29 | return count; 30 | } 31 | 32 | template 33 | __forceinline constexpr bool addition_overflows(T a, T b) 34 | { 35 | return (b != 0 && (a > std::numeric_limits::max() - b)); 36 | } 37 | 38 | template 39 | __forceinline constexpr T sign_bit_mask() 40 | { 41 | // GET MOST SIGNIFICANT BIT 42 | const T bit_count = sizeof(T) * T{8}; 43 | return T{1} << (bit_count - T{1}); 44 | } 45 | 46 | template 47 | __forceinline constexpr bool is_signed(T value) 48 | { 49 | return (value & sign_bit_mask()) == sign_bit_mask(); 50 | } 51 | } -------------------------------------------------------------------------------- /x64-virtualmachine/register.cpp: -------------------------------------------------------------------------------- 1 | #include "register.hpp" 2 | 3 | // REGISTER NAME MAP 4 | const x86::registr::register_name_map_t x86::registr::names = 5 | { 6 | x86::registr::register_names_t { "RAX", "EAX", "AH", "AL" }, 7 | x86::registr::register_names_t { "RCX", "ECX", "CH", "CL" }, 8 | x86::registr::register_names_t { "RDX", "EDX", "DX", "DL" }, 9 | x86::registr::register_names_t { "RBX", "EBX", "BH", "BL" }, 10 | x86::registr::register_names_t { "RSP", "ESP", "SP", "" }, 11 | x86::registr::register_names_t { "RBP", "EBP", "BP", "" }, 12 | x86::registr::register_names_t { "RSI", "ESI", "SI", "" }, 13 | x86::registr::register_names_t { "RDI", "EDI", "DI", "" }, 14 | x86::registr::register_names_t { "R8", "R8D", "R8W", "R8B" }, 15 | x86::registr::register_names_t { "R9", "R9D", "R9W", "R9B" }, 16 | x86::registr::register_names_t { "R10", "R10D", "R10W", "R10B" }, 17 | x86::registr::register_names_t { "R11", "R11D", "R11W", "R11B" }, 18 | x86::registr::register_names_t { "R12", "R12D", "R12W", "R12B" }, 19 | x86::registr::register_names_t { "R13", "R13D", "R13W", "R13B" }, 20 | x86::registr::register_names_t { "R14", "R14D", "R14W", "R14B" }, 21 | x86::registr::register_names_t { "R15", "R15D", "R15W", "R15B" }, 22 | }; 23 | 24 | x86::registr::data_t& x86::registr::general_buffer() 25 | { 26 | return this->m_general_buffer; 27 | } 28 | 29 | x86::registr::register_data& x86::registr::get(std::uint8_t id) 30 | { 31 | return this->general_buffer().at(id); 32 | } 33 | 34 | std::uint8_t*& x86::registr::instruction_pointer() 35 | { 36 | return this->m_instruction_pointer; 37 | } 38 | 39 | x86::registr::flags_t& x86::registr::flags() 40 | { 41 | return this->m_flags; 42 | } 43 | -------------------------------------------------------------------------------- /x64-virtualmachine/register.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | 6 | namespace x86 7 | { 8 | class registr 9 | { 10 | public: 11 | // REGISTER ID's 12 | enum id : std::uint8_t 13 | { 14 | rax, // 0000 15 | rcx, // 0001 16 | rdx, // 0010 17 | rbx, // 0011 18 | rsp, // 0100 19 | rbp, // 0101 20 | rsi, // 0110 21 | rdi, // 0111 22 | r8, // 1000 23 | r9, // 1001 24 | r10, // 1010 25 | r11, // 1011 26 | r12, // 1100 27 | r13, // 1101 28 | r14, // 1110 29 | r15, // 1111 30 | END_OF_REGISTER 31 | }; 32 | 33 | enum size : std::uint8_t 34 | { 35 | qword, 36 | dword, 37 | word, 38 | byte, 39 | END_OF_SIZE 40 | }; 41 | 42 | // REGISTER DATA 43 | union register_data 44 | { 45 | std::uint8_t* ptr; 46 | uint64_t qword; 47 | uint32_t dword; 48 | uint16_t word; 49 | uint8_t byte; 50 | 51 | 52 | std::uint8_t* dword_ptr() 53 | { 54 | std::uint64_t tmp = this->dword; 55 | return reinterpret_cast(tmp); 56 | } 57 | std::uint8_t* word_ptr() 58 | { 59 | std::uint64_t tmp = this->word; 60 | return reinterpret_cast(tmp); 61 | } 62 | }; 63 | 64 | // R/EFLAGS STRUCTURE, DOCUMENTED :) 65 | struct flags_t 66 | { 67 | // 0, Carry flag 68 | // Set if an arithmetic operation generates a carry or a borrow out of 69 | // the mostsignificant bit of the result; cleared otherwise. This flag 70 | // indicates an overflow condition for unsigned integer arithmetic. 71 | // It is also used in multiple precision arithmetic. 72 | std::uint8_t carry : 1; 73 | 74 | private: 75 | // 1, Reserved 76 | std::uint8_t reserved_1 : 1; 77 | public: 78 | 79 | // 2, Parity flag 80 | // Set if the least-significant byte of the result 81 | // contains an even number of 1 bits. 82 | std::uint8_t parity : 1; 83 | 84 | private: 85 | // 3, Reserved 86 | std::uint8_t reserved_3 : 1; 87 | public: 88 | 89 | // 4, Auxiliary carry flag 90 | // Set if an arithmetic operation generates a carry or a 91 | // borrow out of bit 3 of the result. 92 | std::uint8_t auxiliary_carry : 1; 93 | 94 | private: 95 | // 5, Reserved 96 | std::uint8_t reserved_5 : 1; 97 | public: 98 | 99 | // 6, Zero flag 100 | // Set if the result is zero 101 | std::uint8_t zero : 1; 102 | 103 | // 7, Sign flag 104 | // Set equal to the most-significant bit of the result. 105 | std::uint8_t sign : 1; 106 | 107 | // 8, Trap 108 | // Set to enable single-step mode for debugging 109 | std::uint8_t trap : 1; 110 | 111 | // 9, Interrupt 112 | // Set to respond to maskable interrupts 113 | std::uint8_t interrupt : 1; 114 | 115 | // 10, Direction flags 116 | // Controls string instructions. Setting the flag causes string 117 | // instructions to auto-decrement (to process strings from high addresses to low addresses) 118 | // Clearing the flag causes instructions to auto-increment 119 | std::uint8_t direction : 1; 120 | 121 | // 11, Overflow flag 122 | // If integer result is too large a positive number or too small a negative number. 123 | std::uint8_t overflow : 1; 124 | 125 | // 12-13, I/O privilege level 126 | // Indicates current privilege level 127 | // The current privilege level (CPL) of the currently running program or task must be less 128 | // than or equal to the I / O privilege level to access the I / O address space. 129 | std::uint8_t privilege_level : 2; 130 | 131 | // 14, Nested task flag 132 | // Controls the chaining of interrupted and called tasks. Set when the 133 | // current task is linked to the previously executed task; cleared when the current task is not 134 | // linked to another task. 135 | std::uint8_t nested_task : 1; 136 | 137 | private: 138 | // 15, Reserved 139 | std::uint8_t reserved_15 : 1; 140 | public: 141 | 142 | // 16, Resume flag 143 | // Controls the processor's response to debug exceptions. 144 | std::uint8_t resume : 1; 145 | 146 | // 17, VM flag 147 | // Set to enable virtual-8086 mode 148 | std::uint8_t vm : 1; 149 | 150 | // 18, Alignment check flag 151 | // If the AM bit is set in the CR0 register, alignment checking 152 | // of user-mode data accesses is enabled. 153 | // If the SMAP bit is set in the CR4 register, 154 | // explicit supervisor-mode data accesses to user-mode pages are allowed. 155 | std::uint8_t alignment_check : 1; 156 | 157 | // 19, Virtual interrupt flag 158 | // Virtual image of the IF flag. Used in conjunction with the VIP flag. 159 | // (To use this flag and the VIP flag the virtual mode extensions are enabled by setting the VME 160 | // flag in control register CR4.) 161 | std::uint8_t virtual_interrupt : 1; 162 | 163 | // 20, Virtual interrupt pending flag 164 | // Set to indicate that an interrupt is pending; clear when no 165 | // interrupt is pending. (Software sets and clears this flag; the processor only reads it.) Used in 166 | // conjunction with the VIF flag. 167 | std::uint8_t virtual_interrupt_pending : 1; 168 | 169 | // 21, Identification flag 170 | // Support for CPUID instruction 171 | std::uint8_t identification : 1; 172 | 173 | private: 174 | std::uint8_t reserved_22 : 1; 175 | std::uint8_t reserved_23 : 1; 176 | std::uint8_t reserved_24 : 1; 177 | std::uint8_t reserved_25 : 1; 178 | std::uint8_t reserved_26 : 1; 179 | std::uint8_t reserved_27 : 1; 180 | std::uint8_t reserved_28 : 1; 181 | std::uint8_t reserved_29 : 1; 182 | std::uint8_t reserved_30 : 1; 183 | std::uint8_t reserved_31 : 1; 184 | }; 185 | 186 | // GET REGISTER 187 | x86::registr::register_data& get(std::uint8_t id); 188 | 189 | // GET INSTRUCTION POINTER 190 | std::uint8_t*& instruction_pointer(); 191 | 192 | // GET FLAGS 193 | flags_t& flags(); 194 | 195 | // DATA BUFFER 196 | using data_t = std::array; 197 | data_t& general_buffer(); 198 | 199 | // NAME ARRAY FOR DEBUGGING 200 | using register_names_t = std::array; 201 | using register_name_map_t = std::array; 202 | static const register_name_map_t names; 203 | 204 | private: 205 | data_t m_general_buffer; 206 | std::uint8_t* m_instruction_pointer; 207 | flags_t m_flags; 208 | 209 | }; 210 | } -------------------------------------------------------------------------------- /x64-virtualmachine/spinner.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "loggr.hpp" 3 | #include 4 | 5 | class spinner 6 | { 7 | public: 8 | spinner(loggr* new_logger) : m_logger(new_logger) { } 9 | 10 | static constexpr std::uint8_t CHARACTER_SEQUENCE[] = 11 | { 12 | '|', '/', '-', '\\' 13 | }; 14 | 15 | inline void start() 16 | { 17 | if (this->m_active) 18 | { 19 | this->m_logger->log_error("Cannot initialise spinner object more than once!"); 20 | return; 21 | } 22 | 23 | this->m_active = true; 24 | } 25 | 26 | inline void update() 27 | { 28 | if (!this->m_active) 29 | { 30 | this->m_logger->log_error("Cannot initialise spinner object without initialization!"); 31 | return; 32 | } 33 | 34 | 35 | // GET TIME SINCE LAST UPDATE 36 | using clock_t = std::chrono::high_resolution_clock; 37 | const auto time = clock_t::now(); 38 | const auto time_delta = time - m_last_update_time; 39 | const auto duration = std::chrono::duration_cast(time_delta); 40 | 41 | 42 | // ONLY UPDATE SPINNER EVERY x MS 43 | constexpr auto update_time = 150; 44 | if (duration.count() <= update_time) 45 | { 46 | return; 47 | } 48 | 49 | // UPDATE THE SPINNER CHARACTER 50 | this->m_logger->clear_line(); 51 | this->m_logger->log_raw("[{}]", static_cast(spinner::CHARACTER_SEQUENCE[this->m_seq_index])); 52 | 53 | // INCREMENT AND WRAP 54 | this->m_seq_index++; 55 | this->m_seq_index %= sizeof(spinner::CHARACTER_SEQUENCE); 56 | 57 | this->m_last_update_time = time; 58 | 59 | } 60 | inline void stop() 61 | { 62 | if (!this->m_active) 63 | { 64 | this->m_logger->log_error("Spinner is not active!"); 65 | return; 66 | } 67 | 68 | this->m_logger->clear_line(); 69 | this->m_active = false; 70 | } 71 | 72 | private: 73 | const loggr* m_logger; 74 | bool m_active = false; 75 | std::size_t m_seq_index = 0; 76 | std::chrono::steady_clock::time_point m_last_update_time; 77 | }; -------------------------------------------------------------------------------- /x64-virtualmachine/virtual_machine.cpp: -------------------------------------------------------------------------------- 1 | // VM 2 | #include "virtual_machine.hpp" 3 | #include "handlers.hpp" 4 | 5 | // x86 6 | #include "instruction_modrm.hpp" 7 | #include "register.hpp" 8 | 9 | std::vector& virtual_machine::buffer() 10 | { 11 | return this->m_buffer; 12 | } 13 | x86::registr& virtual_machine::context() 14 | { 15 | return this->m_context; 16 | } 17 | 18 | vm::virtual_memory& virtual_machine::memory() 19 | { 20 | return this->m_memory; 21 | } 22 | 23 | void virtual_machine::handle_instruction(x86::instruction& instr) 24 | { 25 | auto vm_instance = const_cast(this); 26 | 27 | // ADD OPCODE CATEGORY? 28 | switch (instr.opcode().as()) 29 | { 30 | 31 | // ADD 32 | case x86::opcode::add_byte: 33 | case x86::opcode::add_displaced_byte: 34 | case x86::opcode::add_displaced_source: 35 | case x86::opcode::add_al: 36 | case x86::opcode::add_rax: 37 | case x86::opcode::add_wide: 38 | case x86::opcode::add_displaced_destination: 39 | case x86::opcode::add_byte_extended: 40 | vm::handler::add::handle(vm_instance, instr); 41 | return; 42 | 43 | default: 44 | vm::handler::unknown(instr); 45 | } 46 | } -------------------------------------------------------------------------------- /x64-virtualmachine/virtual_machine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | #include 6 | 7 | // x86 8 | #include "disasm.hpp" 9 | #include "register.hpp" 10 | 11 | // VM 12 | #include "virtual_stack.hpp" 13 | #include "virtual_memory.hpp" 14 | 15 | // CONSTANTS 16 | constexpr std::uint8_t vm_alignment = 0x8; 17 | constexpr std::uint32_t vm_stack_size = 0x1000; 18 | 19 | // VIRTUAL MACHINE CLASS 20 | class virtual_machine 21 | { 22 | public: 23 | template 24 | virtual_machine(T(&buffer)[N]) : m_buffer(buffer, buffer + N), m_stack(vm_alignment, vm_stack_size) {} 25 | virtual_machine(std::vector buffer) : m_buffer(buffer), m_stack(vm_alignment, vm_stack_size) {} 26 | 27 | // ACCESSORS 28 | std::vector& buffer(); // INSTRUCTION BUFFER 29 | x86::registr& context(); // REGISTER DATA 30 | vm::virtual_memory& memory(); // VIRTUAL MEMORY SPACE 31 | 32 | // INSTRUCTION DISPATCHER 33 | void handle_instruction(x86::instruction& instr); 34 | 35 | // RUN VM ENGINE 36 | template 37 | void run(T offset) 38 | { 39 | // SET UP DISASSEMBLER 40 | auto disassembler = x86::disassembler(this->buffer()); 41 | 42 | // ITERATE INSTRUCTIONS FOR VIRTUALIZATION 43 | disassembler.iterate(offset, [this](x86::instruction instr, std::uint8_t*& instruction_pointer) 44 | { 45 | // SAVE INSTRUCTION POINTER 46 | this->context().instruction_pointer() = instruction_pointer; 47 | 48 | try 49 | { 50 | // VIRTUALIZE INSTRUCTION 51 | this->handle_instruction(instr); 52 | } 53 | catch (std::exception exception) 54 | { 55 | // HANDLE EXCEPTIONS 56 | global::console.log_error_indented<1>(exception.what()); 57 | } 58 | 59 | 60 | // UPDATE INSTRUCTION POINTER 61 | instruction_pointer = this->context().instruction_pointer(); 62 | }); 63 | } 64 | 65 | private: 66 | // INSTRUCTION CODE BUFFER 67 | std::vector m_buffer; 68 | 69 | // REGISTERS 70 | x86::registr m_context; 71 | 72 | // STACK 73 | vm::virtual_stack m_stack; 74 | 75 | // MEMORY 76 | vm::virtual_memory m_memory; 77 | }; -------------------------------------------------------------------------------- /x64-virtualmachine/virtual_memory.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_memory.hpp" 2 | 3 | bool vm::virtual_memory::allocate(std::uint8_t* address, size_t size) 4 | { 5 | // ROUND PAGE DOWN TO NEAREST MULTIPLE 6 | auto page_start = vm::virtual_memory::round_to_page(address); 7 | 8 | // SEE IF ALREADY MAPPED 9 | const auto search = this->address_space().find(page_start); 10 | if (search != this->address_space().end()) 11 | { 12 | return false; 13 | } 14 | 15 | // CREATE REFERENCE-COUNTED SECTION, WHEN ALL REFERENCES ARE REMOVED FROM ADDRESS SPACE 16 | // THE RESPECTIVE PAGES WILL BE FREED AS WELL 17 | auto section = std::make_shared(page_start); 18 | 19 | // DOES ALLOCATION EXCEED CURRENT PAGE? 20 | const auto next_page = page_start + vm::virtual_memory::page_size; 21 | const auto exceeds_page = (address + size) >= next_page; 22 | 23 | // ALLOCATE SINGLE PAGE 24 | if (!exceeds_page) 25 | { 26 | // ADD SECTION TO ADDRESS SPACE 27 | section.get()->add(); 28 | this->address_space().emplace(page_start, section); 29 | } 30 | else 31 | { 32 | auto bytes_left = size; 33 | auto page_index = 0; 34 | auto page_address = address; 35 | do 36 | { 37 | // GET PAGE OFFSET, ONLY FOR FIRST ITERATION 38 | const auto page_offset = vm::virtual_memory::get_page_offset(page_address); 39 | 40 | // CALCULATE ACTUAL BYTES ALLOCATED FROM THE RESPECTIVE SIZE SPECIFIED 41 | const auto count_to_end = vm::virtual_memory::page_size - page_offset; 42 | auto bytes_allocated = std::min(page_offset == 0 ? vm::virtual_memory::page_size : count_to_end, bytes_left); 43 | 44 | // UPDATE ADDRESS TO REFLECT NEW PAGE START 45 | page_address = page_start + vm::virtual_memory::page_size * page_index; 46 | 47 | // ALWAYS ALLOCATE A FULL PAGE 48 | section.get()->add(); 49 | this->address_space().emplace(page_address, section); 50 | 51 | // INCREMENT PAGE INDEX 52 | ++page_index; 53 | 54 | // NEGATE ALLOCATED BYTES FROM SPECIFIED SIZE 55 | bytes_left -= bytes_allocated; 56 | 57 | } while (bytes_left > 0); 58 | } 59 | 60 | return true; 61 | } 62 | 63 | bool vm::virtual_memory::free(std::uint8_t* address) 64 | { 65 | // ROUND PAGE DOWN TO NEAREST MULTIPLE 66 | auto page_start = vm::virtual_memory::round_to_page(address); 67 | 68 | // SEE IF MAPPED 69 | const auto search = this->address_space().find(page_start); 70 | if (search == this->address_space().end()) 71 | { 72 | // FREE ENTIRE SECTION 73 | auto section = search->second; 74 | auto page_count = section.get()->count(); 75 | 76 | // FREE THE SECTION'S PAGES 77 | for (size_t page_index = 0; page_index < page_count; page_index++) 78 | { 79 | this->address_space().erase(page_start + vm::virtual_memory::page_size * page_index); 80 | } 81 | 82 | // SUCCESS 83 | return true; 84 | } 85 | 86 | // NOT MAPPED, FAIL TO RELEASE 87 | return false; 88 | } 89 | 90 | vm::virtual_memory::memory_map_t& vm::virtual_memory::address_space() 91 | { 92 | return this->m_address_space; 93 | } 94 | -------------------------------------------------------------------------------- /x64-virtualmachine/virtual_memory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // VM 10 | #include "virtual_section.hpp" 11 | 12 | namespace vm 13 | { 14 | class virtual_memory 15 | { 16 | public: 17 | static constexpr const size_t page_size = 0x1000; 18 | 19 | bool allocate(std::uint8_t* address, size_t size); 20 | bool free(std::uint8_t* address); 21 | 22 | // PRIVATE TEMPLATE HELPERS 23 | private: 24 | using section_pointer_t = std::_Ptr_base::element_type*; 25 | 26 | template 27 | T handle_iterative_read(uint8_t* address, section_pointer_t section, const size_t& page_index) 28 | { 29 | T result{}; 30 | 31 | auto page_address = address; 32 | auto current_page_index = page_index; 33 | 34 | size_t buffer_offset = 0; 35 | size_t bytes_left = sizeof(T); 36 | 37 | // ITERATIVELY READ ACROSS PAGES 38 | do 39 | { 40 | // GET PAGE OFFSET, ONLY FOR FIRST ITERATION 41 | const auto page_offset = vm::virtual_memory::get_page_offset(page_address); 42 | 43 | // CALCULATE ACTUAL BYTES ALLOCATED FROM THE RESPECTIVE SIZE SPECIFIED 44 | const auto count_to_end = vm::virtual_memory::page_size - page_offset; 45 | const auto bytes_read = std::min(page_offset == 0 ? vm::virtual_memory::page_size : count_to_end, bytes_left); 46 | 47 | // READ BUFFER 48 | auto page_buffer = reinterpret_cast(section->get(current_page_index)); 49 | for (auto i = 0; i < bytes_read; i++) 50 | { 51 | auto buffer = reinterpret_cast(&result); 52 | buffer[buffer_offset + i] = page_buffer[page_offset + i]; 53 | } 54 | 55 | // RESET PAGE ADDRESS 56 | page_address = nullptr; 57 | 58 | // INCREMENT BUFFER OFFSET 59 | buffer_offset += bytes_read; 60 | 61 | // NEGATE READ BYTES FROM COUNTER 62 | bytes_left -= bytes_read; 63 | 64 | // INCREMENT PAGE INDEX 65 | ++current_page_index; 66 | 67 | } while (bytes_left > 0); 68 | 69 | return result; 70 | } 71 | 72 | template 73 | void handle_iterative_write(T& value, uint8_t* address, section_pointer_t section) 74 | { 75 | const auto buffer = reinterpret_cast(&value); 76 | 77 | // CALCULATE SIZE FOR FIRST PAGE AND THEN REST OF BUFFER 78 | size_t buffer_offset = 0; 79 | size_t bytes_left = sizeof(T); 80 | auto current_page_index = vm::virtual_memory::get_page_index(address, section->base()); 81 | 82 | // ITERATIVELY WRITE 83 | auto page_address = address; 84 | do 85 | { 86 | // GET PAGE OFFSET, ONLY FOR FIRST ITERATION 87 | const auto page_offset = vm::virtual_memory::get_page_offset(page_address); 88 | 89 | // CALCULATE ACTUAL BYTES ALLOCATED FROM THE RESPECTIVE SIZE SPECIFIED 90 | const auto count_to_end = vm::virtual_memory::page_size - page_offset; 91 | const auto bytes_written = std::min(page_offset == 0 ? vm::virtual_memory::page_size : count_to_end, bytes_left); 92 | 93 | auto page_buffer = reinterpret_cast(section->get(current_page_index)); 94 | 95 | for (auto i = 0; i < bytes_written; i++) 96 | { 97 | page_buffer[page_offset + i] = buffer[buffer_offset + i]; 98 | } 99 | 100 | // RESET PAGE ADDRESS 101 | page_address = nullptr; 102 | 103 | // INCREMENT BUFFER OFFSET 104 | buffer_offset += bytes_written; 105 | 106 | // NEGATE WRITTEN BYTES FROM COUNTER 107 | bytes_left -= bytes_written; 108 | 109 | // INCREMENT PAGE INDEX 110 | ++current_page_index; 111 | } while (bytes_left > 0); 112 | } 113 | 114 | public: 115 | template 116 | T read(std::uint8_t* address) 117 | { 118 | // ROUND PAGE DOWN TO NEAREST MULTIPLE 119 | auto page_start = vm::virtual_memory::round_to_page(address); 120 | 121 | // SEE IF IN MEMORY PAGE 122 | const auto search = this->address_space().find(page_start); 123 | if (search != this->address_space().end()) 124 | { 125 | auto section = search->second.get(); 126 | 127 | // GET PAGE INDEX 128 | const auto page_index = vm::virtual_memory::get_page_index(page_start, section->base()); 129 | 130 | const size_t buffer_size = sizeof(T); 131 | 132 | // SEE IF DATA IS ON TWO DIFFERENT PAGES 133 | const auto next_page_start = page_start + vm::virtual_memory::page_size; 134 | const bool exceeds_page = (address + sizeof(T) ) >= next_page_start; 135 | 136 | if (!exceeds_page) 137 | { 138 | const auto page_offset = vm::virtual_memory::get_page_offset(address); 139 | return *reinterpret_cast(section->get(page_index) + page_offset); 140 | } 141 | else 142 | { 143 | return handle_iterative_read(address, section, page_index); 144 | } 145 | } 146 | 147 | throw std::exception("Pagefault"); 148 | } 149 | 150 | template 151 | void write(T& value, std::uint8_t* address) 152 | { 153 | // ROUND PAGE DOWN TO NEAREST MULTIPLE 154 | const auto page_start = vm::virtual_memory::round_to_page(address); 155 | 156 | // SEE IF IN MEMORY PAGE 157 | const auto search = this->address_space().find(page_start); 158 | if (search != this->address_space().end()) 159 | { 160 | auto section = search->second.get(); 161 | 162 | // IF IT DOESN'T EXCEED A PAGE, JUST WRITE NORMALLY 163 | const auto next_page_start = page_start + vm::virtual_memory::page_size; 164 | const bool exceeds_page = (address + sizeof(T)) >= next_page_start; 165 | 166 | if (!exceeds_page) 167 | { 168 | const auto page_index = vm::virtual_memory::get_page_index(address, section->base()); 169 | const auto page_offset = vm::virtual_memory::get_page_offset(address); 170 | 171 | *reinterpret_cast(section->get(page_index) + page_offset) = value; 172 | } 173 | else 174 | { 175 | handle_iterative_write(value, address, section); 176 | } 177 | 178 | return; 179 | } 180 | 181 | throw std::exception("Pagefault"); 182 | return; 183 | } 184 | 185 | using memory_map_t = std::map>; 186 | memory_map_t& address_space(); 187 | 188 | private: 189 | template 190 | static constexpr T round_to_page(T address) 191 | { 192 | // CLEAR LOWER 12 BITS 193 | return reinterpret_cast(reinterpret_cast(address) & ~(0xFFF)); 194 | } 195 | 196 | template 197 | static constexpr std::uintptr_t get_page_offset(T address) 198 | { 199 | return reinterpret_cast(address) & (0xFFF); 200 | } 201 | template 202 | static constexpr size_t get_page_index(T address, T base_address) 203 | { 204 | const auto page_delta = vm::virtual_memory::round_to_page(address) - vm::virtual_memory::round_to_page(base_address); 205 | return page_delta / vm::virtual_memory::page_size; 206 | } 207 | 208 | memory_map_t m_address_space; 209 | }; 210 | } -------------------------------------------------------------------------------- /x64-virtualmachine/virtual_section.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_section.hpp" 2 | 3 | 4 | std::uint8_t* vm::virtual_section::get(size_t index) 5 | { 6 | return this->pages().at(index).get(); 7 | } 8 | 9 | size_t vm::virtual_section::count() 10 | { 11 | return this->pages().size(); 12 | } 13 | 14 | std::uint8_t*& vm::virtual_section::base() 15 | { 16 | return this->m_base; 17 | } 18 | 19 | vm::virtual_section::page_list_t& vm::virtual_section::pages() 20 | { 21 | return this->m_pages; 22 | } 23 | -------------------------------------------------------------------------------- /x64-virtualmachine/virtual_section.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | #include 6 | 7 | namespace vm 8 | { 9 | class virtual_section 10 | { 11 | public: 12 | virtual_section(std::uint8_t* base) : m_base(base) {} 13 | 14 | using page_list_t = std::vector>; 15 | 16 | // ALLOCATE PAGE AND ADD TO SECTION 17 | template 18 | void add() 19 | { 20 | this->pages().emplace_back(std::make_unique(N)); 21 | } 22 | 23 | // GET BASE OF nth PAGE 24 | std::uint8_t* get(size_t index); 25 | 26 | // GET PAGE COUNT 27 | size_t count(); 28 | 29 | // GET SECTION BASE 30 | std::uint8_t*& base(); 31 | 32 | private: 33 | // INTERNAL PAGE LIST 34 | page_list_t& pages(); 35 | page_list_t m_pages; 36 | 37 | std::uint8_t* m_base; 38 | }; 39 | } -------------------------------------------------------------------------------- /x64-virtualmachine/virtual_stack.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_stack.hpp" 2 | #include "numerical_helper.hpp" 3 | 4 | namespace vm 5 | { 6 | std::uint8_t* virtual_stack::stack_pointer() 7 | { 8 | // STACK POINTER IS END OF STACK PLUS OFFSET 9 | return m_buffer.data() + this->stack_offset(); 10 | } 11 | 12 | std::int32_t& virtual_stack::stack_offset() 13 | { 14 | // OFFSET FROM STACK END, USED TO CHECK FOR STACK OVERFLOW 15 | return this->m_offset; 16 | } 17 | 18 | std::uint8_t virtual_stack::get_alignment() 19 | { 20 | return this->m_alignment; 21 | } 22 | 23 | std::uint32_t virtual_stack::get_size() 24 | { 25 | return this->m_size; 26 | } 27 | 28 | void virtual_stack::allocate(std::uint32_t size) 29 | { 30 | // CALCULATE ALIGNED SIZE 31 | const auto delta = numerical_helper::round_to_multiple(static_cast(size), static_cast(this->get_alignment())); 32 | 33 | // CHECK FOR OVERFLOW 34 | if (this->stack_offset() - delta < 0) 35 | throw std::exception("Stack overflow"); 36 | 37 | // ALLOCATE MEMORY ON STACK BY SUBTRACTING AMOUNT OF BYTES (ALIGNED) FROM INDEX 38 | this->stack_offset() -= delta; 39 | } 40 | 41 | void virtual_stack::release(std::uint32_t size) 42 | { 43 | // CALCULATE ALIGNED SIZE 44 | const auto delta = numerical_helper::round_to_multiple(static_cast(size), static_cast(this->get_alignment())); 45 | 46 | // CHECK FOR UNDERFLOW 47 | if (this->stack_offset() + delta >= static_cast(this->get_size())) 48 | throw std::exception("Stack underflow"); 49 | 50 | // RELEASE MEMORY ON STACK BY ADDING AMOUNT OF BYTES TO INDEX 51 | this->stack_offset() += delta; 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /x64-virtualmachine/virtual_stack.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // STD 4 | #include 5 | 6 | namespace vm 7 | { 8 | class virtual_stack 9 | { 10 | public: 11 | // CREATE CLASS INSTANCE WITH SPECIFIED ALIGNMENT AND SIZE 12 | virtual_stack(std::uint8_t alignment, std::uint32_t size) : m_alignment(alignment), m_size(size), m_buffer(m_size), m_offset(static_cast(m_size) - 1) { } 13 | 14 | // GET STACK POINTER, CALCULATED FROM STACK END PLUS STACK OFFSET 15 | std::uint8_t* stack_pointer(); 16 | 17 | // GET STACK OFFSET, MODIFIED BY ALLOCATING/RELEASING MEMORY, DEFAULT IS SIZE MINUS ONE 18 | std::int32_t& stack_offset(); 19 | 20 | // ALIGNMENT OF STACK, DEFAULT 0x08 ON MODERN MACHINES 21 | std::uint8_t get_alignment(); 22 | 23 | // SIZE OF STACK, DEFAULT PAGE_SIZE(0x1000) ON MODERN MACHINES 24 | std::uint32_t get_size(); 25 | 26 | // ALLOCATE n='size' BYTES ON STACK, ALIGNED AS SPECIFIED 27 | void allocate(std::uint32_t size); 28 | 29 | // RELEASE n='size' BYTES ON STACK, ALIGNED AS SPECIFIED 30 | void release(std::uint32_t size); 31 | 32 | // PUSH 'value' OF TYPE 'T' ON TOP OF STACK 33 | template 34 | void push(T value) 35 | { 36 | // ALLOCATE STACK CHUNK, ALIGNED AS SPECIFIED 37 | this->allocate(sizeof(T)); 38 | 39 | // WRITE VALUE 40 | *reinterpret_cast(this->stack_pointer()) = value; 41 | } 42 | 43 | // POP TOP OF STACK OF TYPE 'T', RETURN SAID DATA AS TYPE 'T' 44 | template 45 | T pop() 46 | { 47 | // READ VALUE 48 | const T value = *reinterpret_cast(this->stack_pointer()); 49 | 50 | // RELEASE STACK CHUNK, ALIGNED AS SPECIFIED 51 | this->release(sizeof(T)); 52 | 53 | // RETURN VALUE 54 | return value; 55 | } 56 | 57 | private: 58 | 59 | // PRIVATE MEMBER FIELDS, FOR DOCUMENTATION SEE PUBLIC ACCESSORS. 60 | const std::uint8_t m_alignment; 61 | const std::uint32_t m_size; 62 | std::vector m_buffer; 63 | std::int32_t m_offset; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /x64-virtualmachine/vm_test.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "virtual_machine.hpp" 3 | #include "virtual_memory.hpp" 4 | #include "global.hpp" 5 | #include "loggr.hpp" 6 | 7 | template 8 | class vm_tester 9 | { 10 | public: 11 | 12 | // CONSTRUCTORS 13 | 14 | explicit vm_tester(T(&buffer)[N]) : m_vm(buffer) {} 15 | 16 | ~vm_tester() = default; 17 | 18 | // TEST METHODS 19 | 20 | inline void prepare_test() 21 | { 22 | // SETUP REGISTERS FOR EMULATOR TEST 23 | global::console.log("Preparing virtual machine"); 24 | 25 | // RBX 26 | this->m_vm.context().get(x86::registr::id::rbx).qword = 0x1337; 27 | 28 | global::console.log_indented<1>("Prepared RBX"); 29 | 30 | 31 | // RDI 32 | const auto rdi_address = reinterpret_cast(0xFFFFF); 33 | auto rdi_value = 0xABCDEF; 34 | this->m_vm.memory().allocate(rdi_address, sizeof(rdi_value)); 35 | this->m_vm.memory().write(rdi_value, rdi_address + 0x0A); 36 | this->m_vm.context().get(x86::registr::id::rdi).ptr = rdi_address; 37 | global::console.log_indented<1>("Prepared RDI"); 38 | 39 | // R9 40 | const auto r9_address = reinterpret_cast(0xFEEEEFEEEE); 41 | auto r9_value = 0xEEEE; 42 | this->m_vm.memory().allocate(r9_address + 0x420, sizeof(r9_value)); 43 | this->m_vm.memory().write(r9_value, r9_address + 0x420); 44 | this->m_vm.context().get(x86::registr::id::r9).ptr = r9_address; 45 | global::console.log_indented<1>("Prepared R9"); 46 | } 47 | 48 | inline void run() 49 | { 50 | this->print_registers(); 51 | this->print_memory_test(); 52 | 53 | // RUN VM WITH SPECIFIED RELATIVE INSTRUCTION POINTER (BEGINNING) 54 | global::console.log("Running virtual machine"); 55 | this->m_vm.run(0x00); 56 | global::console.log_indented<1>("Finished"); 57 | 58 | this->print_registers(); 59 | this->print_memory_test(); 60 | } 61 | 62 | private: 63 | 64 | // INTERNAL HELPERS 65 | inline void print_registers() 66 | { 67 | global::console.log("Printing registers"); 68 | for (size_t i = 0; i < x86::registr::id::END_OF_REGISTER; i++) 69 | { 70 | const auto id = static_cast(i); 71 | const auto register_name_container = x86::registr::names[id]; 72 | const auto register_name = register_name_container[x86::registr::size::qword]; 73 | const auto register_value = this->m_vm.context().get(id).qword; 74 | 75 | global::console.log_indented<1, true>(register_name, register_value); 76 | } 77 | } 78 | 79 | inline void print_memory_test() 80 | { 81 | global::console.log("Printing memory buffers"); 82 | 83 | const auto r9_address = reinterpret_cast(0xFEEEEFEEEE); 84 | const auto memory_value_before = this->m_vm.memory().read(r9_address + 0x420); 85 | 86 | global::console.log_indented<1, true>("R9+0x420", memory_value_before); 87 | } 88 | 89 | virtual_machine m_vm; 90 | }; -------------------------------------------------------------------------------- /x64-virtualmachine/x64-virtualmachine.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {D974C97F-A6D1-4D3F-94E6-0C6D1B0152D7} 24 | Win32Proj 25 | x64virtualmachine 26 | 10.0.16299.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v141 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v141 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | D:\Sync\Programming\C++\Libraries\Include;$(ExecutablePath) 85 | 86 | 87 | 88 | 89 | 90 | Level3 91 | Disabled 92 | true 93 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Console 98 | true 99 | 100 | 101 | 102 | 103 | NotUsing 104 | Level3 105 | Disabled 106 | true 107 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 108 | true 109 | stdcpp17 110 | 111 | 112 | Console 113 | true 114 | 115 | 116 | 117 | 118 | 119 | 120 | Level3 121 | MaxSpeed 122 | true 123 | true 124 | true 125 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 126 | true 127 | 128 | 129 | Console 130 | true 131 | true 132 | true 133 | 134 | 135 | 136 | 137 | 138 | 139 | Level4 140 | MaxSpeed 141 | true 142 | true 143 | true 144 | NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 145 | true 146 | true 147 | stdcpp17 148 | 149 | 150 | Console 151 | true 152 | true 153 | true 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /x64-virtualmachine/x64-virtualmachine.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {e177d2bd-b174-42f7-b9b0-16ed0a35d2d8} 18 | 19 | 20 | {65f3eb1f-7ecf-48d2-8083-fc09f1582ffd} 21 | 22 | 23 | {d0d19ab7-f745-4dbd-b838-9251b00ad1ef} 24 | 25 | 26 | {c2a794f4-8180-4c07-80bf-fc538598e335} 27 | 28 | 29 | {8f510547-e72d-4a7c-9402-96f58a123496} 30 | 31 | 32 | {cbffe629-de2a-4930-adc0-e6cc23162392} 33 | 34 | 35 | {9077b451-52c7-40ab-8e53-30afeea45eb3} 36 | 37 | 38 | {215c799a-c44a-4150-9ca6-bc160bfb1fae} 39 | 40 | 41 | {09c92ea0-fb8d-491d-83eb-3b420db9c550} 42 | 43 | 44 | {869ab47c-e14c-405a-8fe1-a4031ca9751f} 45 | 46 | 47 | {6279c470-1834-446c-b3d6-b634a0b2962d} 48 | 49 | 50 | {3ade731a-ea9a-4c6a-9d63-dff06fe22031} 51 | 52 | 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files\x86 59 | 60 | 61 | Source Files\x86 62 | 63 | 64 | Source Files\vm 65 | 66 | 67 | Source Files\vm 68 | 69 | 70 | Source Files\x86 71 | 72 | 73 | Source Files\x86 74 | 75 | 76 | Source Files\vm\handlers\add 77 | 78 | 79 | Source Files\vm\handlers 80 | 81 | 82 | Source Files\x86 83 | 84 | 85 | Source Files\vm 86 | 87 | 88 | Source Files\vm 89 | 90 | 91 | Source Files\vm 92 | 93 | 94 | Source Files\vm\handlers\add 95 | 96 | 97 | Source Files\vm\handlers\add 98 | 99 | 100 | Source Files\vm\handlers\add 101 | 102 | 103 | Source Files 104 | 105 | 106 | Source Files\fmt 107 | 108 | 109 | Source Files\fmt 110 | 111 | 112 | 113 | 114 | Header Files 115 | 116 | 117 | Header Files\x86 118 | 119 | 120 | Header Files\x86 121 | 122 | 123 | Header Files\x86 124 | 125 | 126 | Header Files\x86 127 | 128 | 129 | Header Files\x86 130 | 131 | 132 | Header Files\x86 133 | 134 | 135 | Header Files\vm 136 | 137 | 138 | Header Files\vm 139 | 140 | 141 | Header Files\x86 142 | 143 | 144 | Header Files\x86 145 | 146 | 147 | Header Files\vm\handlers 148 | 149 | 150 | Header Files\vm\handlers 151 | 152 | 153 | Header Files 154 | 155 | 156 | Header Files\vm\memory 157 | 158 | 159 | Header Files\vm\memory 160 | 161 | 162 | Header Files\vm\handlers\add 163 | 164 | 165 | Header Files\vm\handlers\add 166 | 167 | 168 | Header Files\vm\handlers\add 169 | 170 | 171 | Header Files\vm\handlers\add 172 | 173 | 174 | Header Files\logger 175 | 176 | 177 | Header Files\logger 178 | 179 | 180 | Header Files 181 | 182 | 183 | Header Files\vm_tester 184 | 185 | 186 | --------------------------------------------------------------------------------