GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 5 / 0 / 5
Functions: 100.0% 2 / 0 / 2
Branches: 87.5% 14 / 0 / 16

src/internal/export_resolution.hpp
Line Branch Exec Source
1 #ifndef DETOURMODKIT_INTERNAL_EXPORT_RESOLUTION_HPP
2 #define DETOURMODKIT_INTERNAL_EXPORT_RESOLUTION_HPP
3
4 /**
5 * @file internal/export_resolution.hpp
6 * @brief The resolved physical provenance of a named export, for callers that must tell two names for one EAT entry
7 * apart from two genuinely independent signals.
8 * @details A module's export table maps many names onto one function array. Two names may share an ordinal, or two
9 * ordinals may carry one function RVA, and in both cases a single patched instruction breaks every name that
10 * reaches it. A quorum that counts those names separately reports corroboration it does not have, so the
11 * resolver publishes the physical site it actually read instead of only the address it returns.
12 */
13
14 #include "DetourModKit/address.hpp"
15 #include "DetourModKit/scan.hpp"
16
17 #include <cstdint>
18 #include <string_view>
19
20 namespace DetourModKit
21 {
22 namespace detail
23 {
24 /**
25 * @struct ExportResolution
26 * @brief Where a resolved export physically came from.
27 * @details @ref module_base identifies the mapping, since two images cannot occupy one base at once, and it is
28 * what keeps two modules that export the same RVA apart. @ref function_index is the slot in
29 * AddressOfFunctions the name mapped to, and @ref function_rva is the value read out of it.
30 */
31 struct ExportResolution
32 {
33 std::uintptr_t module_base{0};
34 std::uint32_t function_index{0};
35 std::uint32_t function_rva{0};
36 Address target{};
37
38
3/4
✓ Branch 2 → 3 taken 25 times.
✓ Branch 2 → 6 taken 87 times.
✓ Branch 4 → 5 taken 25 times.
✗ Branch 4 → 6 not taken.
112 [[nodiscard]] constexpr bool present() const noexcept { return module_base != 0 && target.raw() != 0; }
39 };
40
41 /**
42 * @brief True when both resolutions name one physical export site.
43 * @details Equal slots are the same table entry read twice; equal RVAs in one image are the same code reached
44 * through two entries. Either makes the pair one failure domain, so a quorum must count them once.
45 * An absent resolution correlates with nothing: only a member that can name its physical source may
46 * take part in this test.
47 */
48 91 [[nodiscard]] constexpr bool same_export_site(const ExportResolution &a, const ExportResolution &b) noexcept
49 {
50
7/8
✓ Branch 3 → 4 taken 7 times.
✓ Branch 3 → 7 taken 84 times.
✓ Branch 5 → 6 taken 7 times.
✗ Branch 5 → 7 not taken.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 6 times.
✓ Branch 9 → 10 taken 85 times.
✓ Branch 9 → 11 taken 6 times.
91 if (!a.present() || !b.present() || a.module_base != b.module_base)
51 {
52 85 return false;
53 }
54
4/4
✓ Branch 11 → 12 taken 3 times.
✓ Branch 11 → 13 taken 3 times.
✓ Branch 12 → 13 taken 2 times.
✓ Branch 12 → 14 taken 1 time.
6 return a.function_index == b.function_index || a.function_rva == b.function_rva;
55 }
56
57 /**
58 * @brief @ref scan::resolve_export, additionally publishing the physical site the match was read from.
59 * @param export_name Export name to resolve; matched byte-exactly and case-sensitively.
60 * @param module Module scope to walk.
61 * @param out Receives the resolved provenance on success; left default on any failure.
62 * @return The resolved address, or the same typed failure @ref scan::resolve_export reports.
63 */
64 [[nodiscard]] Result<Address>
65 resolve_export_with_provenance(std::string_view export_name, Region module, ExportResolution &out) noexcept;
66 } // namespace detail
67 } // namespace DetourModKit
68
69 #endif // DETOURMODKIT_INTERNAL_EXPORT_RESOLUTION_HPP
70