├── .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 |
--------------------------------------------------------------------------------