> For the complete documentation index, see [llms.txt](https://docs.sealights.io/knowledgebase/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sealights.io/knowledgebase/setup-and-configuration/troubleshooting-faq/c++/why-does-sealights-use-static-instrumentation-for-c-c++-msvc.md).

# Why Does SeaLights Use Static Instrumentation for C/C++ (MSVC)?

### TL;DR

* C++ compiles directly to native machine code, so — like Go — there is no runtime VM to hook into. SeaLights uses **build-time static instrumentation**.
* On MSVC, instrumentation adds a lightweight **`_penter` callback at the start of each function** to track execution during test runs. Your **business logic and control flow stay unchanged**.
* The scan also writes a **`.slmap` file next to each binary**, mapping each function's **RVA** (which changes on every compile) to its **stable fully qualified name (FQN)**.
* Only the `.slmap` files must travel with their binaries. The **tracer DLLs, token, and build session ID can live centrally** (on the `PATH`) or come from **environment variables** — they don't need to go into your application installer.
* Run the **instrumented build in test environments only**, and keep production on your regular build.

{% hint style="info" %}
For implementation guidance or questions about your specific environment, please don't hesitate to contact your SeaLights support representative or solutions engineer.
{% endhint %}

### Why doesn't C/C++ support runtime instrumentation like Java or .NET?

Java and .NET run on an intermediate runtime — the JVM and the CLR. That runtime lets tools attach as agents or profilers and modify bytecode/IL **in memory at runtime** to collect coverage.

C++ has no such layer. It compiles straight to native machine code, with no intermediate representation and no runtime hook exposed during execution. That means **runtime instrumentation is not possible** for C++, and coverage instrumentation has to happen earlier — **at build time**.

### What does SeaLights do instead?

During the build, SeaLights performs **static instrumentation**:

* On MSVC, a lightweight **`_penter` callback** is added at the **start of every function**, using the compiler's function-entry hook. When the function runs, the callback records it — this is what enables method-level coverage.
* The change is limited to that entry hook. The **function's own logic and control flow stay exactly as written** — nothing related to your business logic is touched.
* Alongside the compiled binaries, the scanner writes one **`.slmap` file per binary** so that coverage can be tied back to stable, human-readable function names (see the next section).

{% hint style="warning" %}
What SeaLights does with static instrumentation in C++ is conceptually the same as what happens "behind the scenes" during dynamic instrumentation in Java/.NET. The difference is **when** it happens — at build time instead of at runtime.
{% endhint %}

When the SeaLights runtime isn't present — for example, in a production build — no coverage is collected, and there is no coverage-related runtime overhead.

### What is the `.slmap` file, and why must it sit next to its binary?

At runtime, SeaLights needs to know **which function ran** and match it to the **same function in your source** — reliably, and comparably across builds. Native code makes that hard: a function's location inside a binary, its **RVA (relative virtual address)**, **changes on every compilation**, even when the source is identical. The RVA alone can't identify a function from one build to the next.

The `.slmap` solves this. It's a small **binary file, specific to MSVC**, laid out as:

`<header> <number of entries>` followed, for each function, by `<RVA> <hash of the function's FQN>`

* **RVA** — where the function sits inside that exact `.dll` / `.exe`. Changes every compile.
* **FQN** — the function's **fully qualified name**, which is **stable across builds**.

At runtime, the flow is: the `_penter` hook reports the **RVA** that executed → the `.slmap` resolves that RVA to the **stable FQN** → coverage maps to the same function no matter how the addresses shifted.

Because those RVAs are only valid for the exact binary they were generated from, **each `.slmap` must sit beside its own binary**. It can't be reused, centralized, or published as a separate package.

### What files does SeaLights add, and where do they go?

SeaLights adds files in two groups, with two different placement rules:

<table><thead><tr><th width="182.75">File</th><th>What it is</th><th>Where it lives</th></tr></thead><tbody><tr><td><code>sltracer_x64.dll</code> / <code>sltracer_x86.dll</code></td><td>The runtime tracer that <code>_penter</code> calls into. Same for every build.</td><td>Central, on the <code>PATH</code> (or copied next to the application <code>.exe</code>s).</td></tr><tr><td>Token</td><td>The agent authentication token.</td><td>A secret <strong>environment variable</strong> (recommended), or a token file in the central location.</td></tr><tr><td><code>buildSessionID.txt</code></td><td>The SeaLights-generated UUID for the build. Version-specific value.</td><td>A central file kept in sync with the deployed version, an environment variable, or bundled in the application installer for simplicity.</td></tr><tr><td><code>.slmap</code> files</td><td>Per-binary RVA → FQN map.</td><td><strong>Beside each binary (mandatory).</strong></td></tr></tbody></table>

{% hint style="info" %}
Only the `.slmap` files are tied to your binaries. Everything else can be managed centrally or through environment variables, so it doesn't need to go into your application installer.
{% endhint %}

### How do we deploy safely (test vs. production)?

The goal is simple: **instrumented binaries run in test environments only**, and production keeps its regular build.

**Recommended — separate builds.** Produce an instrumented build for testing and a clean, uninstrumented build for production. Your CI/CD picks the right one per environment. This gives the strongest separation and keeps production completely untouched.

To deploy into a test environment:

1. Deploy the build output (for example, `.\build\Debug\*`), keeping **each `.slmap` beside its binary**.
2. Make the tracer discoverable — either add the agent directory to the `PATH`, or copy `sltracer_x64.dll` / `sltracer_x86.dll` next to the application `.exe`s under test.
3. Provide the **token** (a secret environment variable is cleanest) and the **build session ID**.

Making the tracer discoverable via `PATH` (PowerShell):

```powershell
# Add the SeaLights agent directory so the tracer DLLs are found by the test processes
$env:PATH = "C:\agents\sealights;$env:PATH"
```

Since the tracer lives in the SeaLights agent bundle that's already required on the test machine, adding the agent directory to `PATH` is usually all you need.

{% hint style="warning" %}
Where possible, run your coverage tests against the **Debug** build. Release-mode optimizations — inlining, dead-code elimination, identical-code folding — can drop or merge functions that were instrumented at scan time. Those functions then never fire their `_penter` hook at runtime and can appear as uncovered even when the code effectively ran. A Debug build keeps functions intact, so the coverage you see lines up with what was scanned.
{% endhint %}

### Related

* [Why Does SeaLights Use Static Instrumentation for Go?](https://docs.sealights.io/knowledgebase/setup-and-configuration/troubleshooting-faq/golang/why-does-sealights-use-static-instrumentation-for-go) — the same build-time approach, applied to Go.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.sealights.io/knowledgebase/setup-and-configuration/troubleshooting-faq/c++/why-does-sealights-use-static-instrumentation-for-c-c++-msvc.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
