├── .gitignore ├── src ├── DrCodeCov │ ├── DrCodeCov.vcxproj.user │ ├── formats │ │ ├── formats.h │ │ ├── formats.cpp │ │ ├── format_base.h │ │ ├── format_idc.h │ │ ├── format_bin.h │ │ └── format_drcov.h │ ├── coverage.h │ ├── modules.h │ ├── DrCodeCov.vcxproj.filters │ ├── main.cpp │ ├── modules.cpp │ └── DrCodeCov.vcxproj └── DrCodeCov.sln ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | /src/Objects 3 | -------------------------------------------------------------------------------- /src/DrCodeCov/DrCodeCov.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/DrCodeCov/formats/formats.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "format_base.h" 4 | 5 | void output_formats_init(); 6 | void output_formats_cleanup(); 7 | 8 | OutputFormatBase* output_format_find(const char *name); 9 | -------------------------------------------------------------------------------- /src/DrCodeCov/coverage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #pragma pack(push, 1) 6 | struct CoverageHeader_t 7 | { 8 | enum { k_Magic = 0xDEADBEEF }; 9 | 10 | uint32_t magic; 11 | uint32_t size; 12 | uint64_t imageStart; 13 | uint64_t imageEnd; 14 | uint32_t timestamp; 15 | uint32_t checksum; 16 | }; 17 | 18 | struct Coverage_t 19 | { 20 | enum 21 | { 22 | UNREACHED = 0, // Unreached. 23 | INSTR_START = (1 << 0), // Begin of instruction 24 | INSTR_PART = (1 << 1), // Part of instruction. 25 | BRANCH_START = (1 << 2), // Branch starts with this instructions. 26 | BRANCH_END = (1 << 3), // Branch ends with this instructions. 27 | }; 28 | uint8_t flags; 29 | }; 30 | 31 | #pragma pack(pop) 32 | -------------------------------------------------------------------------------- /src/DrCodeCov/modules.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "dr_api.h" 8 | #include "drmgr.h" 9 | #include "coverage.h" 10 | 11 | struct ModuleEntry_t 12 | { 13 | app_pc imageStart; 14 | app_pc imageEnd; 15 | 16 | Coverage_t *coverage; 17 | module_data_t *data; 18 | bool loaded; 19 | 20 | size_t getImageSize() const 21 | { 22 | return (size_t)(imageEnd - imageStart); 23 | } 24 | }; 25 | 26 | void modules_init(); 27 | void modules_cleanup(); 28 | void modules_lock(); 29 | void modules_unlock(); 30 | 31 | void modules_add(void *drcontext, const module_data_t *info, bool loaded); 32 | void module_remove(void *drcontext, const module_data_t *info); 33 | 34 | void modules_tag_instr(void *drcontext, app_pc va, int len, bool isBranch, bool isBranchEnd); 35 | void modules_dump(const std::string& format, const std::string& outputDir); 36 | -------------------------------------------------------------------------------- /src/DrCodeCov/formats/formats.cpp: -------------------------------------------------------------------------------- 1 | #include "formats.h" 2 | #include "format_bin.h" 3 | #include "format_drcov.h" 4 | #include "format_idc.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | static std::vector> _outputFormats; 11 | 12 | void output_formats_init() 13 | { 14 | _outputFormats.emplace_back( std::make_unique() ); 15 | _outputFormats.emplace_back(std::make_unique() ); 16 | _outputFormats.emplace_back(std::make_unique() ); 17 | } 18 | 19 | void output_formats_cleanup() 20 | { 21 | _outputFormats.clear(); 22 | } 23 | 24 | OutputFormatBase* output_format_find(const char *name) 25 | { 26 | auto it = std::find_if(_outputFormats.begin(), _outputFormats.end(), [name](const std::unique_ptr& fmt)->bool 27 | { 28 | return _stricmp(fmt->name(), name) == 0; 29 | }); 30 | 31 | if(it == _outputFormats.end()) 32 | return nullptr; 33 | 34 | return (*it).get(); 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 ζeh Matt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DrCodeCov 2 | Code Coverage client for DynamoRIO 3 | 4 | # About 5 | Its slightly different from DynamoRIO's drcov in terms of data. DrCodeCov will create for each loaded module a bitmap that is the size of the entire image, it will mark each byte individually which can tell us following things: 6 | - Is instruction start. 7 | - Is instruction part. 8 | - Is branch. 9 | - Unreached. 10 | 11 | DrCodeCov will not count hits, this is something I did not need. You can identify which code is executed or if code jumps into parts of instruction operands, this is common in obfuscated code. 12 | 13 | # DrCov format. 14 | DrCodeCov can output the same format as drcov, specify this via the client option "-format drcov". We however suggest using the binary format for extended details. You will be also able to feed the drcov format directly to Lighthouse, see https://github.com/gaasedelen/lighthouse for more details. 15 | 16 | # Building 17 | The project currently comes with a Visual Studio 2017 project. Make sure you have set environment variable DYNAMORIO_HOME to your DynamoRIO directory. Open the project in Visual Studio and choose your desired configuration to build. 18 | -------------------------------------------------------------------------------- /src/DrCodeCov/DrCodeCov.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | formats 8 | 9 | 10 | 11 | 12 | 13 | formats 14 | 15 | 16 | formats 17 | 18 | 19 | formats 20 | 21 | 22 | formats 23 | 24 | 25 | formats 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | {08a1465e-bba1-42a0-a165-923eff74d3c0} 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/DrCodeCov/formats/format_base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "dr_api.h" 8 | #include "drmgr.h" 9 | 10 | struct ModuleEntry_t; 11 | 12 | class OutputFormatBase 13 | { 14 | private: 15 | std::string _outputDirectory; 16 | 17 | public: 18 | void setOutputDirectory(const std::string& outputDir) 19 | { 20 | _outputDirectory = outputDir; 21 | } 22 | 23 | virtual const char* name() const = 0; 24 | 25 | protected: 26 | const std::string& getOutputDirectory() const 27 | { 28 | return _outputDirectory; 29 | } 30 | 31 | std::string getModuleFileName(const char *fullPath) const 32 | { 33 | char moduleName[1024]; 34 | dr_snprintf(moduleName, 1024, "%s", fullPath); 35 | 36 | // Sanitize slashes 37 | for (auto& c : moduleName) 38 | { 39 | if (c == '/') 40 | c = '\\'; 41 | } 42 | 43 | const char *modName = strrchr(moduleName, '\\'); 44 | if (modName) 45 | { 46 | dr_snprintf(moduleName, 1024, "%s", modName + 1); 47 | } 48 | else 49 | { 50 | dr_snprintf(moduleName, 1024, "%s", fullPath); 51 | } 52 | 53 | return moduleName; 54 | } 55 | 56 | public: 57 | virtual bool createOutput(const std::vector& modules) = 0; 58 | }; 59 | 60 | -------------------------------------------------------------------------------- /src/DrCodeCov.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2016 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DrCodeCov", "DrCodeCov\DrCodeCov.vcxproj", "{644CBB09-B946-46BC-BF5C-0ECB8E1AA8E3}" 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 | {644CBB09-B946-46BC-BF5C-0ECB8E1AA8E3}.Debug|x64.ActiveCfg = Debug|x64 17 | {644CBB09-B946-46BC-BF5C-0ECB8E1AA8E3}.Debug|x64.Build.0 = Debug|x64 18 | {644CBB09-B946-46BC-BF5C-0ECB8E1AA8E3}.Debug|x86.ActiveCfg = Debug|Win32 19 | {644CBB09-B946-46BC-BF5C-0ECB8E1AA8E3}.Debug|x86.Build.0 = Debug|Win32 20 | {644CBB09-B946-46BC-BF5C-0ECB8E1AA8E3}.Release|x64.ActiveCfg = Release|x64 21 | {644CBB09-B946-46BC-BF5C-0ECB8E1AA8E3}.Release|x64.Build.0 = Release|x64 22 | {644CBB09-B946-46BC-BF5C-0ECB8E1AA8E3}.Release|x86.ActiveCfg = Release|Win32 23 | {644CBB09-B946-46BC-BF5C-0ECB8E1AA8E3}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {C99573FC-1556-4260-B4F8-1BDB800292DE} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/DrCodeCov/formats/format_idc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "format_base.h" 4 | #include "../coverage.h" 5 | #include "../modules.h" 6 | 7 | class OutputFormatIDC : public OutputFormatBase 8 | { 9 | private: 10 | void dumpModule(file_t f, const ModuleEntry_t& mod) 11 | { 12 | dr_fprintf(f, "#include \n" 13 | "static main() {\n"); 14 | #ifdef _WIN64 15 | dr_fprintf(f, "\tauto imageBase = 0x%.16llX;\n", (void*)mod.imageStart); 16 | #else 17 | dr_fprintf(f, "\tauto imageBase = 0x%08X;\n", (void*)mod.imageStart); 18 | #endif 19 | size_t reps = 0; 20 | for (size_t n = 0; n < mod.getImageSize(); n++) 21 | { 22 | if (mod.coverage[n].flags & Coverage_t::BRANCH_START) 23 | { 24 | uint32_t rva = (uint32_t)(n); 25 | dr_fprintf(f, "\tMakeCode(imageBase+0x%08X);\n", rva); 26 | } 27 | } 28 | dr_fprintf(f, "}\n"); 29 | } 30 | 31 | public: 32 | virtual const char* name() const override 33 | { 34 | return "idc"; 35 | } 36 | 37 | virtual bool createOutput(const std::vector& modules) override 38 | { 39 | char outFile[1024] = {}; 40 | 41 | std::string outputFolder = getOutputDirectory(); 42 | dr_create_dir(outputFolder.c_str()); 43 | 44 | for (auto& mod : modules) 45 | { 46 | std::string modName = getModuleFileName(mod.data->full_path); 47 | dr_snprintf(outFile, 1024, "%s\\%s.idc", outputFolder.c_str(), modName.c_str()); 48 | 49 | file_t f = dr_open_file(outFile, DR_FILE_WRITE_REQUIRE_NEW); 50 | if (f == INVALID_FILE) 51 | { 52 | dr_fprintf(STDERR, "Unable to open file for writing: %s", outFile); 53 | continue; 54 | } 55 | 56 | dumpModule(f, mod); 57 | 58 | dr_close_file(f); 59 | } 60 | 61 | return true; 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /src/DrCodeCov/formats/format_bin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "format_base.h" 4 | #include "../coverage.h" 5 | #include "../modules.h" 6 | 7 | class OutputFormatBinary : public OutputFormatBase 8 | { 9 | private: 10 | void dumpModule(file_t f, const ModuleEntry_t& mod) 11 | { 12 | CoverageHeader_t header; 13 | header.magic = CoverageHeader_t::k_Magic; 14 | header.imageStart = (uint64_t)mod.imageStart; 15 | header.imageEnd = (uint64_t)mod.imageEnd; 16 | #ifdef WINDOWS 17 | header.checksum = mod.data->checksum; 18 | header.timestamp = mod.data->timestamp; 19 | #else 20 | // FIXME: Use something else to identify the binary. 21 | header.checksum = 0x1c1c1c1c; 22 | header.timestamp = 0x2c2c2c2c; 23 | #endif 24 | header.size = (uint32_t)(mod.getImageSize() * sizeof(Coverage_t)); 25 | 26 | // Write header. 27 | dr_write_file(f, &header, sizeof(header)); 28 | 29 | // Write bitmap. 30 | dr_write_file(f, mod.coverage, header.size); 31 | } 32 | 33 | public: 34 | virtual const char* name() const override 35 | { 36 | return "bin"; 37 | } 38 | 39 | virtual bool createOutput(const std::vector& modules) override 40 | { 41 | char outFile[1024] = {}; 42 | 43 | std::string outputFolder = getOutputDirectory(); 44 | dr_create_dir(outputFolder.c_str()); 45 | 46 | for (auto& mod : modules) 47 | { 48 | std::string modName = getModuleFileName(mod.data->full_path); 49 | dr_snprintf(outFile, 1024, "%s\\%s_bin.cov", outputFolder.c_str(), modName.c_str()); 50 | 51 | file_t f = dr_open_file(outFile, DR_FILE_WRITE_REQUIRE_NEW); 52 | if (f == INVALID_FILE) 53 | { 54 | dr_fprintf(STDERR, "Unable to open file for writing: %s", outFile); 55 | continue; 56 | } 57 | 58 | dumpModule(f, mod); 59 | 60 | dr_close_file(f); 61 | } 62 | 63 | return true; 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /src/DrCodeCov/main.cpp: -------------------------------------------------------------------------------- 1 | #include "dr_api.h" 2 | #include "drmgr.h" 3 | #include "modules.h" 4 | #include "droption.h" 5 | #include "formats/formats.h" 6 | 7 | static droption_t op_format(DROPTION_SCOPE_CLIENT, 8 | "format", 9 | "", 10 | "Output Format", 11 | "Possible options: bin , idc, drcov"); 12 | 13 | static droption_t op_outputDir(DROPTION_SCOPE_CLIENT, 14 | "output_dir", 15 | "", 16 | "Output Directory", 17 | "If empty it will use the current directory"); 18 | 19 | static void event_module_load(void *drcontext, const module_data_t *info, bool loaded) 20 | { 21 | modules_add(drcontext, info, loaded); 22 | } 23 | 24 | static void event_module_unload(void *drcontext, const module_data_t *info) 25 | { 26 | module_remove(drcontext, info); 27 | } 28 | 29 | static void event_exit(void) 30 | { 31 | std::string fmt = op_format.get_value(); 32 | if (fmt.empty()) 33 | fmt = "bin"; 34 | 35 | std::string outputDirectory = op_outputDir.get_value(); 36 | if (outputDirectory.empty()) 37 | { 38 | uint32_t pid = (uint32_t)dr_get_process_id(); 39 | 40 | char curDir[1024] = {}; 41 | dr_get_current_directory(curDir, 1024); 42 | 43 | char outPath[1024] = {}; 44 | dr_snprintf(outPath, 1024, "%s\\coverage.%08X", curDir, pid); 45 | 46 | dr_create_dir(outPath); 47 | 48 | outputDirectory = outPath; 49 | } 50 | 51 | modules_dump(fmt, outputDirectory); 52 | modules_cleanup(); 53 | output_formats_cleanup(); 54 | 55 | drmgr_exit(); 56 | } 57 | 58 | static dr_emit_flags_t event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr, bool for_trace, bool translating, void *user_data) 59 | { 60 | if (!instr_is_app(instr)) 61 | return DR_EMIT_DEFAULT; 62 | 63 | const bool isBranch = drmgr_is_first_instr(drcontext, instr); 64 | const bool isBranchEnd = drmgr_is_last_instr(drcontext, instr); 65 | const int instrLength = instr_length(drcontext, instr); 66 | const app_pc va = instr_get_app_pc(instr); 67 | 68 | modules_tag_instr(drcontext, va, instrLength, isBranch, isBranchEnd); 69 | 70 | return DR_EMIT_DEFAULT; 71 | } 72 | 73 | DR_EXPORT void dr_client_main(client_id_t id, int argc, const char *argv[]) 74 | { 75 | dr_set_client_name("DrCodeCoverage", ""); 76 | 77 | std::string parse_err; 78 | 79 | if (!droption_parser_t::parse_argv(DROPTION_SCOPE_CLIENT, argc, argv, &parse_err, nullptr)) 80 | { 81 | dr_fprintf(STDERR, "Usage error: %s", parse_err.c_str()); 82 | dr_abort(); 83 | } 84 | 85 | std::string fmt = op_format.get_value(); 86 | if(fmt.empty()) 87 | fmt = "bin"; 88 | 89 | if (fmt != "bin" && fmt != "drcov" && fmt != "idc") 90 | { 91 | dr_fprintf(STDERR, "Invalid output format: %s", fmt.c_str()); 92 | dr_abort(); 93 | } 94 | 95 | drmgr_init(); 96 | dr_register_exit_event(event_exit); 97 | 98 | if (!drmgr_register_bb_instrumentation_event(NULL, event_app_instruction, NULL)) 99 | { 100 | dr_messagebox("drmgr_register_bb_instrumentation_event failed"); 101 | } 102 | if (!drmgr_register_module_load_event(event_module_load)) 103 | { 104 | dr_messagebox("drmgr_register_module_load_event failed"); 105 | } 106 | if (!drmgr_register_module_unload_event(event_module_unload)) 107 | { 108 | dr_messagebox("drmgr_register_module_unload_event failed"); 109 | } 110 | 111 | modules_init(); 112 | output_formats_init(); 113 | } 114 | 115 | -------------------------------------------------------------------------------- /src/DrCodeCov/formats/format_drcov.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "format_base.h" 4 | #include "../coverage.h" 5 | #include "../modules.h" 6 | 7 | #include 8 | 9 | #pragma pack(push, 1) 10 | struct drcov_bb 11 | { 12 | uint32_t start; 13 | uint16_t size; 14 | uint16_t id; 15 | }; 16 | #pragma pack(pop) 17 | 18 | class OutputFormatDrCov : public OutputFormatBase 19 | { 20 | private: 21 | void writeHeader(file_t f, size_t numOfModules) 22 | { 23 | dr_fprintf(f, "DRCOV VERSION: 2\n"); 24 | dr_fprintf(f, "DRCOV FLAVOR: drcov\n"); 25 | dr_fprintf(f, "Module Table: version 2, count %u\n", (uint32_t)numOfModules); 26 | dr_fprintf(f, "Columns: id, base, end, entry, checksum, timestamp, path\n"); 27 | } 28 | 29 | void writeModuleData(file_t f, const std::vector& modules) 30 | { 31 | uint32_t cnt = 0; 32 | for (auto &i : modules) 33 | { 34 | std::string moduleName = i.data->full_path; 35 | void * startAddr = i.imageStart; 36 | void * endAddr = i.imageEnd; 37 | void * entryPoint = i.data->entry_point; 38 | uint32_t checksum = i.data->checksum; 39 | uint32_t timestamp = i.data->timestamp; 40 | 41 | dr_fprintf(f, "%2u, %p, %p, %p, 0x%x, 0x%x, %s\n", 42 | cnt, startAddr, endAddr, entryPoint, checksum, timestamp, moduleName.c_str()); 43 | 44 | cnt++; 45 | } 46 | } 47 | 48 | uint16_t countBlockSize(Coverage_t *coverageArray, size_t index, size_t arraySize) 49 | { 50 | uint16_t size = 1; 51 | 52 | size_t maxIterations = arraySize - index; 53 | for (size_t i = 1; i < maxIterations; i++, size++) 54 | { 55 | if (coverageArray[index + i].flags & Coverage_t::BRANCH_END || 56 | coverageArray[index + i].flags == Coverage_t::UNREACHED) 57 | { 58 | break; 59 | } 60 | } 61 | 62 | return size; 63 | } 64 | 65 | void writeBasicBlockData(file_t f, const std::vector& modules) 66 | { 67 | std::list drBasicBlocks; 68 | 69 | uint32_t modId = 0; 70 | for (auto &mod : modules) 71 | { 72 | drcov_bb bbl; 73 | 74 | for (size_t n = 0; n < mod.getImageSize(); n++) 75 | { 76 | bbl.id = 0; 77 | bbl.start = 0; 78 | bbl.size = 0; 79 | 80 | if (mod.coverage[n].flags & Coverage_t::BRANCH_START) 81 | { 82 | bbl.id = modId; // Module Id 83 | bbl.start = (uint32_t)(n); // RVA 84 | bbl.size = countBlockSize(mod.coverage, n, mod.getImageSize()); 85 | drBasicBlocks.push_back(bbl); 86 | 87 | n = n + bbl.size - 1; 88 | } 89 | } 90 | 91 | modId++; 92 | } 93 | 94 | dr_fprintf(f, "BB Table: %u bbs\n", drBasicBlocks.size()); 95 | 96 | for (auto &bbl : drBasicBlocks) 97 | { 98 | dr_write_file(f, &bbl, sizeof(bbl)); 99 | } 100 | } 101 | 102 | void writeDrCovFile(file_t f, const std::vector& modules) 103 | { 104 | writeHeader(f, modules.size()); 105 | writeModuleData(f, modules); 106 | writeBasicBlockData(f, modules); 107 | } 108 | 109 | public: 110 | virtual const char* name() const override 111 | { 112 | return "drcov"; 113 | } 114 | 115 | virtual bool createOutput(const std::vector& modules) override 116 | { 117 | char outFile[1024] = {}; 118 | uint32_t pid = (uint32_t)dr_get_process_id(); 119 | 120 | std::string outputFolder = getOutputDirectory(); 121 | dr_create_dir(outputFolder.c_str()); 122 | 123 | dr_snprintf(outFile, 1024, "%s\\proc_%d.cov", outputFolder.c_str(), pid); 124 | file_t f = dr_open_file(outFile, DR_FILE_WRITE_REQUIRE_NEW); 125 | if (f == INVALID_FILE) 126 | { 127 | dr_fprintf(STDERR, "Unable to open file for writing: %s", outFile); 128 | return false; 129 | } 130 | 131 | writeDrCovFile(f, modules); 132 | 133 | dr_close_file(f); 134 | 135 | return true; 136 | } 137 | }; 138 | -------------------------------------------------------------------------------- /src/DrCodeCov/modules.cpp: -------------------------------------------------------------------------------- 1 | #include "modules.h" 2 | #include "coverage.h" 3 | #include "formats/formats.h" 4 | 5 | #include 6 | #include 7 | 8 | // Variables. 9 | static std::vector _modules; 10 | static void* _modLock = nullptr; 11 | 12 | void modules_init() 13 | { 14 | _modLock = dr_mutex_create(); 15 | 16 | // Avoid all sorts of allocations, we just need it for managment. 17 | _modules.reserve(0x1000); 18 | } 19 | 20 | void modules_cleanup() 21 | { 22 | dr_mutex_destroy(_modLock); 23 | } 24 | 25 | void modules_lock() 26 | { 27 | dr_mutex_lock(_modLock); 28 | } 29 | 30 | void modules_unlock() 31 | { 32 | dr_mutex_unlock(_modLock); 33 | } 34 | 35 | static ModuleEntry_t* module_find(app_pc va, bool requireLoaded) 36 | { 37 | for(auto& mod : _modules) 38 | { 39 | if (requireLoaded && mod.loaded == false) 40 | { 41 | continue; 42 | } 43 | if (va >= mod.imageStart && va < mod.imageEnd) 44 | { 45 | return &mod; 46 | } 47 | } 48 | 49 | return nullptr; 50 | } 51 | 52 | static ModuleEntry_t* module_find_by_data(const module_data_t *data, bool requireLoaded) 53 | { 54 | for (auto& mod : _modules) 55 | { 56 | if (requireLoaded && mod.loaded == false) 57 | continue; 58 | 59 | if (requireLoaded) 60 | { 61 | if (mod.data->start != data->start || 62 | mod.data->end != data->end) 63 | { 64 | continue; 65 | } 66 | } 67 | 68 | if (mod.data->timestamp == data->timestamp && 69 | mod.data->checksum == data->checksum && 70 | mod.data->module_internal_size == data->module_internal_size && 71 | mod.data->entry_point == data->entry_point) 72 | { 73 | return &mod; 74 | } 75 | } 76 | return nullptr; 77 | } 78 | 79 | void modules_tag_instr(void *drcontext, app_pc va, int len, bool isBranch, bool isBranchEnd) 80 | { 81 | modules_lock(); 82 | 83 | ModuleEntry_t* mod = module_find(va, true); 84 | 85 | if (!mod) 86 | { 87 | modules_unlock(); 88 | return; 89 | } 90 | 91 | size_t offset = (va - mod->imageStart); 92 | mod->coverage[offset].flags |= Coverage_t::INSTR_START; 93 | 94 | if(isBranch) 95 | mod->coverage[offset].flags |= Coverage_t::BRANCH_START; 96 | if(isBranchEnd) 97 | mod->coverage[offset].flags |= Coverage_t::BRANCH_END; 98 | 99 | for (int i = 1; i < len; i++) 100 | { 101 | mod->coverage[offset + i].flags |= Coverage_t::INSTR_PART; 102 | } 103 | 104 | modules_unlock(); 105 | } 106 | 107 | void modules_add(void *drcontext, const module_data_t *info, bool loaded) 108 | { 109 | modules_lock(); 110 | 111 | //dr_messagebox("Module load %s\n", info->full_path); 112 | 113 | ModuleEntry_t *entry = module_find_by_data(info, false); 114 | if (!entry) 115 | { 116 | // New entry. 117 | size_t idx = _modules.size(); 118 | _modules.resize(idx + 1); 119 | 120 | entry = &_modules[idx]; 121 | entry->imageStart = info->start; 122 | entry->imageEnd = info->end; 123 | entry->data = dr_copy_module_data(info); 124 | 125 | const size_t coverageSize = sizeof(Coverage_t) * entry->getImageSize(); 126 | entry->coverage = (Coverage_t*)dr_global_alloc(coverageSize); 127 | 128 | memset(entry->coverage, 0, coverageSize); 129 | } 130 | else 131 | { 132 | // Update only. 133 | entry->imageStart = info->start; 134 | entry->imageEnd = info->end; 135 | } 136 | 137 | entry->loaded = true; 138 | 139 | // FIXME: Sort everything for binary search. 140 | /* 141 | std::sort(_modules.begin(), _modules.end(), [](const ModuleEntry_t& a, const ModuleEntry_t& b)->bool 142 | { 143 | return a.imageStart < b.imageStart; 144 | }); 145 | */ 146 | 147 | modules_unlock(); 148 | } 149 | 150 | void module_remove(void *drcontext, const module_data_t *info) 151 | { 152 | modules_lock(); 153 | 154 | ModuleEntry_t *mod = module_find_by_data(info, true); 155 | if (mod) 156 | { 157 | mod->loaded = false; 158 | } 159 | 160 | modules_unlock(); 161 | } 162 | 163 | void modules_dump(const std::string& format, const std::string& outputDir) 164 | { 165 | OutputFormatBase* fmtOut = output_format_find(format.c_str()); 166 | 167 | if (!fmtOut) 168 | { 169 | dr_messagebox("Invalid output format selected: %s", format.c_str()); 170 | return; 171 | } 172 | 173 | fmtOut->setOutputDirectory(outputDir); 174 | fmtOut->createOutput(_modules); 175 | } 176 | 177 | -------------------------------------------------------------------------------- /src/DrCodeCov/DrCodeCov.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 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 15.0 39 | {644CBB09-B946-46BC-BF5C-0ECB8E1AA8E3} 40 | Win32Proj 41 | DrCodeCov 42 | 10.0.17134.0 43 | 44 | 45 | 46 | DynamicLibrary 47 | true 48 | v141 49 | Unicode 50 | 51 | 52 | DynamicLibrary 53 | false 54 | v141 55 | true 56 | Unicode 57 | 58 | 59 | DynamicLibrary 60 | true 61 | v141 62 | Unicode 63 | 64 | 65 | DynamicLibrary 66 | false 67 | v141 68 | true 69 | Unicode 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | true 91 | $(SolutionDir)Objects\$(ProjectName)\$(Configuration)\ 92 | $(SolutionDir)Build\ 93 | $(ProjectName)_x86_debug 94 | $(VC_IncludePath);$(WindowsSDK_IncludePath);%DYNAMORIO_HOME%\ext\include;%DYNAMORIO_HOME%\include 95 | 96 | 97 | true 98 | $(SolutionDir)..\build\ 99 | $(SolutionDir)Objects\$(ProjectName)\$(Configuration)\ 100 | $(ProjectName)_x64_debug 101 | 102 | 103 | false 104 | $(SolutionDir)Build\ 105 | $(SolutionDir)Objects\$(ProjectName)\$(Configuration)\ 106 | $(ProjectName)_x86 107 | $(VC_IncludePath);$(WindowsSDK_IncludePath);%DYNAMORIO_HOME%\ext\include;%DYNAMORIO_HOME%\include 108 | 109 | 110 | false 111 | $(SolutionDir)..\build\ 112 | $(SolutionDir)Objects\$(ProjectName)\$(Configuration)\ 113 | $(ProjectName)_x64 114 | $(VC_IncludePath);$(WindowsSDK_IncludePath);%DYNAMORIO_HOME%\ext\include;%DYNAMORIO_HOME%\include 115 | 116 | 117 | 118 | NotUsing 119 | Level3 120 | Disabled 121 | true 122 | WIN32;_DEBUG;DRCODECOV_EXPORTS;_WINDOWS;_USRDLL;WINDOWS;X86_32;%(PreprocessorDefinitions) 123 | true 124 | %DYNAMORIO_HOME%\ext\include;%DYNAMORIO_HOME%\include;%(AdditionalIncludeDirectories) 125 | 126 | 127 | Windows 128 | true 129 | drmgr.lib;drreg.lib;drsyms.lib;drutil.lib;drwrap.lib;drx.lib;dynamorio.lib;%(AdditionalDependencies) 130 | %DYNAMORIO_HOME%\ext\lib32\debug;%DYNAMORIO_HOME%\lib32\debug;%(AdditionalLibraryDirectories) 131 | 132 | 133 | 134 | 135 | 136 | NotUsing 137 | Level3 138 | Disabled 139 | true 140 | _DEBUG;DRCODECOV_EXPORTS;_WINDOWS;_USRDLL;WINDOWS;X86_64;%(PreprocessorDefinitions) 141 | true 142 | %DYNAMORIO_HOME%\ext\include;%DYNAMORIO_HOME%\include;%(AdditionalIncludeDirectories) 143 | 144 | 145 | Windows 146 | true 147 | drmgr.lib;drreg.lib;drsyms.lib;drutil.lib;drwrap.lib;drx.lib;dynamorio.lib;%(AdditionalDependencies) 148 | %DYNAMORIO_HOME%\ext\lib64\debug;%DYNAMORIO_HOME%\lib64\debug;%(AdditionalLibraryDirectories) 149 | 150 | 151 | 152 | 153 | 154 | NotUsing 155 | Level3 156 | MaxSpeed 157 | true 158 | true 159 | true 160 | WIN32;NDEBUG;DRCODECOV_EXPORTS;_WINDOWS;_USRDLL;WINDOWS;X86_32;%(PreprocessorDefinitions) 161 | true 162 | MultiThreaded 163 | %DYNAMORIO_HOME%\ext\include;%DYNAMORIO_HOME%\include;%(AdditionalIncludeDirectories) 164 | 165 | 166 | Windows 167 | true 168 | true 169 | true 170 | drmgr.lib;drreg.lib;drsyms.lib;drutil.lib;drwrap.lib;drx.lib;dynamorio.lib;%(AdditionalDependencies) 171 | %DYNAMORIO_HOME%\ext\lib32\release;%DYNAMORIO_HOME%\lib32\release;%(AdditionalLibraryDirectories) 172 | 173 | 174 | 175 | 176 | 177 | NotUsing 178 | Level3 179 | MaxSpeed 180 | true 181 | true 182 | true 183 | NDEBUG;DRCODECOV_EXPORTS;_WINDOWS;_USRDLL;WINDOWS;X86_64;%(PreprocessorDefinitions) 184 | true 185 | MultiThreaded 186 | %DYNAMORIO_HOME%\ext\include;%DYNAMORIO_HOME%\include;%(AdditionalIncludeDirectories) 187 | 188 | 189 | Windows 190 | true 191 | true 192 | true 193 | drmgr.lib;drreg.lib;drsyms.lib;drutil.lib;drwrap.lib;drx.lib;dynamorio.lib;%(AdditionalDependencies) 194 | %DYNAMORIO_HOME%\ext\lib64\release;%DYNAMORIO_HOME%\lib64\release;%(AdditionalLibraryDirectories) 195 | 196 | 197 | 198 | 199 | 200 | 201 | --------------------------------------------------------------------------------