up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
This commit is contained in:
@@ -65,10 +65,11 @@ internal sealed class NativeCallgraphBuilder
|
||||
.ThenBy(e => e.CallSiteOffset)
|
||||
.ToImmutableArray();
|
||||
|
||||
// Sort roots per CONTRACT-INIT-ROOTS-401: by phase (numeric), then order, then target ID
|
||||
var roots = _roots
|
||||
.OrderBy(r => r.BinaryPath)
|
||||
.ThenBy(r => r.Phase)
|
||||
.OrderBy(r => (int)r.Phase)
|
||||
.ThenBy(r => r.Order)
|
||||
.ThenBy(r => r.TargetId, StringComparer.Ordinal)
|
||||
.ToImmutableArray();
|
||||
|
||||
var unknowns = _unknowns
|
||||
@@ -130,34 +131,34 @@ internal sealed class NativeCallgraphBuilder
|
||||
|
||||
private void AddSyntheticRoots(ElfFile elf)
|
||||
{
|
||||
// Find and add _start
|
||||
AddRootIfExists(elf, "_start", NativeRootType.Start, "load", 0);
|
||||
// Find and add _start (load phase)
|
||||
AddRootIfExists(elf, "_start", NativeRootType.Start, "entry_point", NativeRootPhase.Load, 0);
|
||||
|
||||
// Find and add _init
|
||||
AddRootIfExists(elf, "_init", NativeRootType.Init, "init", 0);
|
||||
// Find and add _init (init phase, before init_array)
|
||||
AddRootIfExists(elf, "_init", NativeRootType.Init, "DT_INIT", NativeRootPhase.Init, 0);
|
||||
|
||||
// Find and add _fini
|
||||
AddRootIfExists(elf, "_fini", NativeRootType.Fini, "fini", 0);
|
||||
// Find and add _fini (fini phase)
|
||||
AddRootIfExists(elf, "_fini", NativeRootType.Fini, "DT_FINI", NativeRootPhase.Fini, 0);
|
||||
|
||||
// Find and add main
|
||||
AddRootIfExists(elf, "main", NativeRootType.Main, "main", 0);
|
||||
// Find and add main (main phase)
|
||||
AddRootIfExists(elf, "main", NativeRootType.Main, "main", NativeRootPhase.Main, 0);
|
||||
|
||||
// Add preinit_array entries
|
||||
// Add preinit_array entries (preinit phase)
|
||||
for (var i = 0; i < elf.PreInitArraySymbols.Length; i++)
|
||||
{
|
||||
var symName = elf.PreInitArraySymbols[i];
|
||||
AddRootByName(elf, symName, NativeRootType.PreInitArray, "preinit", i);
|
||||
AddRootByName(elf, symName, NativeRootType.PreInitArray, "preinit_array", NativeRootPhase.PreInit, i);
|
||||
}
|
||||
|
||||
// Add init_array entries
|
||||
// Add init_array entries (init phase, order starts after DT_INIT)
|
||||
for (var i = 0; i < elf.InitArraySymbols.Length; i++)
|
||||
{
|
||||
var symName = elf.InitArraySymbols[i];
|
||||
AddRootByName(elf, symName, NativeRootType.InitArray, "init", i);
|
||||
AddRootByName(elf, symName, NativeRootType.InitArray, "init_array", NativeRootPhase.Init, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddRootIfExists(ElfFile elf, string symbolName, NativeRootType rootType, string phase, int order)
|
||||
private void AddRootIfExists(ElfFile elf, string symbolName, NativeRootType rootType, string source, NativeRootPhase phase, int order)
|
||||
{
|
||||
var sym = elf.Symbols.Concat(elf.DynamicSymbols)
|
||||
.FirstOrDefault(s => s.Name == symbolName && s.Type == ElfSymbolType.Func);
|
||||
@@ -170,18 +171,23 @@ internal sealed class NativeCallgraphBuilder
|
||||
var binding = sym.Binding.ToString().ToLowerInvariant();
|
||||
var symbolId = NativeGraphIdentifiers.ComputeSymbolId(sym.Name, sym.Value, sym.Size, binding);
|
||||
|
||||
var rootId = NativeGraphIdentifiers.ComputeRootId(symbolId, rootType, order);
|
||||
// Use CONTRACT-INIT-ROOTS-401 compliant root ID format
|
||||
var rootId = NativeGraphIdentifiers.ComputeRootId(phase, order, symbolId);
|
||||
|
||||
_roots.Add(new NativeSyntheticRoot(
|
||||
RootId: rootId,
|
||||
TargetId: symbolId,
|
||||
RootType: rootType,
|
||||
Source: source,
|
||||
BinaryPath: elf.Path,
|
||||
BuildId: elf.BuildId,
|
||||
Phase: phase,
|
||||
Order: order));
|
||||
Order: order,
|
||||
IsResolved: true,
|
||||
TargetAddress: sym.Value));
|
||||
}
|
||||
|
||||
private void AddRootByName(ElfFile elf, string symbolName, NativeRootType rootType, string phase, int order)
|
||||
private void AddRootByName(ElfFile elf, string symbolName, NativeRootType rootType, string source, NativeRootPhase phase, int order)
|
||||
{
|
||||
// Check if it's a hex address placeholder
|
||||
if (symbolName.StartsWith("func_0x", StringComparison.Ordinal))
|
||||
@@ -191,14 +197,28 @@ internal sealed class NativeCallgraphBuilder
|
||||
_unknowns.Add(new NativeUnknown(
|
||||
UnknownId: unknownId,
|
||||
UnknownType: NativeUnknownType.UnresolvedTarget,
|
||||
SourceId: $"{elf.Path}:{phase}:{order}",
|
||||
SourceId: $"{elf.Path}:{source}:{order}",
|
||||
Name: symbolName,
|
||||
Reason: "Init array entry could not be resolved to a symbol",
|
||||
BinaryPath: elf.Path));
|
||||
|
||||
// Still add an unresolved root per CONTRACT-INIT-ROOTS-401
|
||||
var unresolvedRootId = $"root:{phase.ToString().ToLowerInvariant()}:{order}:unknown:{symbolName}";
|
||||
_roots.Add(new NativeSyntheticRoot(
|
||||
RootId: unresolvedRootId,
|
||||
TargetId: $"unknown:{symbolName}",
|
||||
RootType: rootType,
|
||||
Source: source,
|
||||
BinaryPath: elf.Path,
|
||||
BuildId: elf.BuildId,
|
||||
Phase: phase,
|
||||
Order: order,
|
||||
IsResolved: false,
|
||||
TargetAddress: null));
|
||||
return;
|
||||
}
|
||||
|
||||
AddRootIfExists(elf, symbolName, rootType, phase, order);
|
||||
AddRootIfExists(elf, symbolName, rootType, source, phase, order);
|
||||
}
|
||||
|
||||
private void AddRelocationEdges(ElfFile elf)
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
namespace StellaOps.Scanner.Analyzers.Native.Internal.Demangle;
|
||||
|
||||
/// <summary>
|
||||
/// Composite demangler that tries multiple demanglers in order.
|
||||
/// Per DECISION-NATIVE-TOOLCHAIN-401: per-language managed demanglers with native fallback.
|
||||
/// </summary>
|
||||
internal sealed class CompositeDemangler : ISymbolDemangler
|
||||
{
|
||||
private readonly ISymbolDemangler[] _demanglers;
|
||||
|
||||
public CompositeDemangler(params ISymbolDemangler[] demanglers)
|
||||
{
|
||||
_demanglers = demanglers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a default composite demangler with built-in demanglers.
|
||||
/// </summary>
|
||||
public static CompositeDemangler CreateDefault() =>
|
||||
new(
|
||||
new ItaniumAbiDemangler(),
|
||||
new RustDemangler(),
|
||||
new HeuristicDemangler());
|
||||
|
||||
public bool TryDemangle(string mangledName, out DemangleResult result)
|
||||
{
|
||||
if (string.IsNullOrEmpty(mangledName))
|
||||
{
|
||||
result = DemangleResult.Failed(mangledName ?? string.Empty, "Empty symbol name");
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var demangler in _demanglers)
|
||||
{
|
||||
if (demangler.TryDemangle(mangledName, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = DemangleResult.Failed(mangledName, "No demangler recognized the symbol format");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Itanium C++ ABI demangler (GCC/Clang style).
|
||||
/// </summary>
|
||||
internal sealed class ItaniumAbiDemangler : ISymbolDemangler
|
||||
{
|
||||
public bool TryDemangle(string mangledName, out DemangleResult result)
|
||||
{
|
||||
result = default!;
|
||||
|
||||
// Itanium ABI symbols start with _Z
|
||||
if (!mangledName.StartsWith("_Z", StringComparison.Ordinal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Basic demangling for common patterns
|
||||
// Full implementation would use a proper parser or external library
|
||||
var demangled = TryParseItaniumSymbol(mangledName);
|
||||
if (demangled is not null)
|
||||
{
|
||||
result = DemangleResult.Success(mangledName, demangled, DemangleSource.ItaniumAbi);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the mangled name with heuristic confidence if we recognized but couldn't parse
|
||||
result = DemangleResult.Heuristic(mangledName, mangledName, 0.6);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string? TryParseItaniumSymbol(string mangled)
|
||||
{
|
||||
// Simple pattern matching for common cases
|
||||
// Full implementation would use a complete Itanium ABI parser
|
||||
|
||||
if (mangled.StartsWith("_ZN", StringComparison.Ordinal))
|
||||
{
|
||||
// Nested name: _ZN<length>name<length>name...E<signature>
|
||||
return ParseNestedName(mangled);
|
||||
}
|
||||
|
||||
if (mangled.StartsWith("_Z", StringComparison.Ordinal))
|
||||
{
|
||||
// Simple name: _Z<length>name<signature>
|
||||
return ParseSimpleName(mangled);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string? ParseNestedName(string mangled)
|
||||
{
|
||||
// Basic nested name parsing: _ZN4Foo3BarE -> Foo::Bar
|
||||
var components = new List<string>();
|
||||
var pos = 3; // Skip "_ZN"
|
||||
|
||||
while (pos < mangled.Length)
|
||||
{
|
||||
if (mangled[pos] == 'E')
|
||||
{
|
||||
break; // End of nested name
|
||||
}
|
||||
|
||||
// Read length
|
||||
var lengthStart = pos;
|
||||
while (pos < mangled.Length && char.IsDigit(mangled[pos]))
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (pos == lengthStart)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var length = int.Parse(mangled[lengthStart..pos]);
|
||||
if (pos + length > mangled.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
components.Add(mangled.Substring(pos, length));
|
||||
pos += length;
|
||||
}
|
||||
|
||||
if (components.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return string.Join("::", components);
|
||||
}
|
||||
|
||||
private static string? ParseSimpleName(string mangled)
|
||||
{
|
||||
// Basic simple name parsing: _Z3foo -> foo
|
||||
var pos = 2; // Skip "_Z"
|
||||
|
||||
// Read length
|
||||
var lengthStart = pos;
|
||||
while (pos < mangled.Length && char.IsDigit(mangled[pos]))
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (pos == lengthStart)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var length = int.Parse(mangled[lengthStart..pos]);
|
||||
if (pos + length > mangled.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return mangled.Substring(pos, length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rust symbol demangler.
|
||||
/// </summary>
|
||||
internal sealed class RustDemangler : ISymbolDemangler
|
||||
{
|
||||
public bool TryDemangle(string mangledName, out DemangleResult result)
|
||||
{
|
||||
result = default!;
|
||||
|
||||
// Rust symbols start with _ZN or _R (new scheme) with specific patterns
|
||||
// Legacy: _ZN...17h<hash>E (contains 17h followed by hex hash)
|
||||
// v0: _R...
|
||||
|
||||
if (!mangledName.StartsWith("_ZN", StringComparison.Ordinal) &&
|
||||
!mangledName.StartsWith("_R", StringComparison.Ordinal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for Rust hash pattern (17h followed by 16 hex chars)
|
||||
var hashIndex = mangledName.IndexOf("17h", StringComparison.Ordinal);
|
||||
if (hashIndex < 0 && !mangledName.StartsWith("_R", StringComparison.Ordinal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Basic demangling - strip hash suffix for legacy format
|
||||
var demangled = TryParseRustSymbol(mangledName);
|
||||
if (demangled is not null)
|
||||
{
|
||||
result = DemangleResult.Success(mangledName, demangled, DemangleSource.Rust);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Heuristic if we recognized the pattern
|
||||
result = DemangleResult.Heuristic(mangledName, mangledName, 0.5);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string? TryParseRustSymbol(string mangled)
|
||||
{
|
||||
// Simple pattern: extract components before hash
|
||||
if (!mangled.StartsWith("_ZN", StringComparison.Ordinal))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var hashIndex = mangled.IndexOf("17h", StringComparison.Ordinal);
|
||||
var endIndex = hashIndex > 0 ? hashIndex : mangled.Length - 1;
|
||||
|
||||
var components = new List<string>();
|
||||
var pos = 3; // Skip "_ZN"
|
||||
|
||||
while (pos < endIndex)
|
||||
{
|
||||
if (mangled[pos] == 'E')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var lengthStart = pos;
|
||||
while (pos < endIndex && char.IsDigit(mangled[pos]))
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (pos == lengthStart)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var length = int.Parse(mangled[lengthStart..pos]);
|
||||
if (pos + length > mangled.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
components.Add(mangled.Substring(pos, length));
|
||||
pos += length;
|
||||
}
|
||||
|
||||
if (components.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return string.Join("::", components);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Heuristic demangler for unrecognized formats.
|
||||
/// </summary>
|
||||
internal sealed class HeuristicDemangler : ISymbolDemangler
|
||||
{
|
||||
public bool TryDemangle(string mangledName, out DemangleResult result)
|
||||
{
|
||||
// If the name doesn't look mangled, return it as-is with high confidence
|
||||
if (!LooksMangled(mangledName))
|
||||
{
|
||||
result = DemangleResult.Success(mangledName, mangledName, DemangleSource.Heuristic);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise return the mangled name with low confidence
|
||||
result = DemangleResult.Failed(mangledName, "Unrecognized mangling scheme");
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool LooksMangled(string name) =>
|
||||
// Common mangling prefixes
|
||||
name.StartsWith("_Z", StringComparison.Ordinal) ||
|
||||
name.StartsWith("?", StringComparison.Ordinal) || // MSVC
|
||||
name.StartsWith("_R", StringComparison.Ordinal) || // Rust v0
|
||||
name.StartsWith("__Z", StringComparison.Ordinal) || // macOS Itanium
|
||||
name.Contains("@@", StringComparison.Ordinal); // MSVC decorated
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
namespace StellaOps.Scanner.Analyzers.Native.Internal.Demangle;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for symbol demangling services.
|
||||
/// Per DECISION-NATIVE-TOOLCHAIN-401 specification.
|
||||
/// </summary>
|
||||
public interface ISymbolDemangler
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempts to demangle a symbol name.
|
||||
/// </summary>
|
||||
/// <param name="mangledName">The mangled symbol name.</param>
|
||||
/// <param name="result">The demangling result if successful.</param>
|
||||
/// <returns>True if demangling was successful, false otherwise.</returns>
|
||||
bool TryDemangle(string mangledName, out DemangleResult result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of a demangling operation.
|
||||
/// </summary>
|
||||
/// <param name="Mangled">Original mangled name.</param>
|
||||
/// <param name="Demangled">Demangled human-readable name.</param>
|
||||
/// <param name="Source">Demangling source (e.g., itanium-abi, msvc, rust).</param>
|
||||
/// <param name="Confidence">Confidence level (1.0 for definite, lower for heuristic).</param>
|
||||
/// <param name="Error">Error message if demangling partially failed.</param>
|
||||
public sealed record DemangleResult(
|
||||
string Mangled,
|
||||
string? Demangled,
|
||||
DemangleSource Source,
|
||||
double Confidence,
|
||||
string? Error = null)
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a successful demangling result.
|
||||
/// </summary>
|
||||
public static DemangleResult Success(string mangled, string demangled, DemangleSource source) =>
|
||||
new(mangled, demangled, source, 1.0);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed demangling result.
|
||||
/// </summary>
|
||||
public static DemangleResult Failed(string mangled, string? error = null) =>
|
||||
new(mangled, null, DemangleSource.None, 0.3, error);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a heuristic demangling result.
|
||||
/// </summary>
|
||||
public static DemangleResult Heuristic(string mangled, string demangled, double confidence) =>
|
||||
new(mangled, demangled, DemangleSource.Heuristic, confidence);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Source of demangling operation per CONTRACT-NATIVE-TOOLCHAIN-401.
|
||||
/// </summary>
|
||||
public enum DemangleSource
|
||||
{
|
||||
/// <summary>Itanium C++ ABI (GCC/Clang).</summary>
|
||||
ItaniumAbi,
|
||||
|
||||
/// <summary>Microsoft Visual C++.</summary>
|
||||
Msvc,
|
||||
|
||||
/// <summary>Rust mangling.</summary>
|
||||
Rust,
|
||||
|
||||
/// <summary>Swift mangling.</summary>
|
||||
Swift,
|
||||
|
||||
/// <summary>D language mangling.</summary>
|
||||
D,
|
||||
|
||||
/// <summary>Native tool fallback.</summary>
|
||||
Fallback,
|
||||
|
||||
/// <summary>Pattern-based heuristic.</summary>
|
||||
Heuristic,
|
||||
|
||||
/// <summary>No demangling available.</summary>
|
||||
None,
|
||||
}
|
||||
@@ -335,12 +335,13 @@ internal static class ElfReader
|
||||
return null;
|
||||
}
|
||||
|
||||
return Convert.ToHexString(gnuBuildId.Descriptor.Span).ToLowerInvariant();
|
||||
var hexBuildId = Convert.ToHexString(gnuBuildId.Descriptor.Span).ToLowerInvariant();
|
||||
return $"gnu-build-id:{hexBuildId}";
|
||||
}
|
||||
|
||||
private static string FormatCodeId(string buildId)
|
||||
{
|
||||
// Format as ELF code-id (same as build-id for ELF)
|
||||
// For ELF, code-id uses the prefixed build-id directly
|
||||
return buildId;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ internal static class NativeGraphDsseWriter
|
||||
TargetId: root.TargetId,
|
||||
RootType: root.RootType.ToString().ToLowerInvariant(),
|
||||
BinaryPath: root.BinaryPath,
|
||||
Phase: root.Phase,
|
||||
Phase: root.Phase.ToString().ToLowerInvariant(),
|
||||
Order: root.Order);
|
||||
|
||||
await WriteLineAsync(writer, record, cancellationToken);
|
||||
@@ -160,7 +160,7 @@ internal static class NativeGraphDsseWriter
|
||||
TargetId: r.TargetId,
|
||||
RootType: r.RootType.ToString().ToLowerInvariant(),
|
||||
BinaryPath: r.BinaryPath,
|
||||
Phase: r.Phase,
|
||||
Phase: r.Phase.ToString().ToLowerInvariant(),
|
||||
Order: r.Order)).ToArray(),
|
||||
Unknowns: graph.Unknowns.OrderBy(u => u.UnknownId).Select(u => new NdjsonUnknownPayload(
|
||||
UnknownId: u.UnknownId,
|
||||
|
||||
@@ -92,20 +92,51 @@ public enum NativeEdgeType
|
||||
|
||||
/// <summary>
|
||||
/// A synthetic root in the call graph (entry points that don't have callers).
|
||||
/// Per CONTRACT-INIT-ROOTS-401 specification.
|
||||
/// </summary>
|
||||
/// <param name="RootId">Deterministic root identifier.</param>
|
||||
/// <param name="RootId">Deterministic root identifier: root:{phase}:{order}:{target_id}.</param>
|
||||
/// <param name="TargetId">SymbolId of the target function.</param>
|
||||
/// <param name="RootType">Type of synthetic root.</param>
|
||||
/// <param name="Source">Source of the root (e.g., init_array, DT_INIT, preinit_array, etc.).</param>
|
||||
/// <param name="BinaryPath">Path to the containing binary.</param>
|
||||
/// <param name="Phase">Execution phase (load, init, main, fini).</param>
|
||||
/// <param name="BuildId">Build-ID of the binary (e.g., gnu-build-id:...).</param>
|
||||
/// <param name="Phase">Execution phase (load=0, preinit=1, init=2, main=3, fini=4).</param>
|
||||
/// <param name="Order">Order within the phase (for init arrays).</param>
|
||||
/// <param name="IsResolved">Whether the target was successfully resolved.</param>
|
||||
/// <param name="TargetAddress">Address of the target function if available.</param>
|
||||
public sealed record NativeSyntheticRoot(
|
||||
string RootId,
|
||||
string TargetId,
|
||||
NativeRootType RootType,
|
||||
string Source,
|
||||
string BinaryPath,
|
||||
string Phase,
|
||||
int Order);
|
||||
string? BuildId,
|
||||
NativeRootPhase Phase,
|
||||
int Order,
|
||||
bool IsResolved = true,
|
||||
ulong? TargetAddress = null);
|
||||
|
||||
/// <summary>
|
||||
/// Execution phase for synthetic roots.
|
||||
/// Ordered by when they execute during program lifecycle.
|
||||
/// </summary>
|
||||
public enum NativeRootPhase
|
||||
{
|
||||
/// <summary>Dynamic linker resolution phase (order=0).</summary>
|
||||
Load = 0,
|
||||
|
||||
/// <summary>Before dynamic init - DT_PREINIT_ARRAY (order=1).</summary>
|
||||
PreInit = 1,
|
||||
|
||||
/// <summary>During initialization - DT_INIT, init_array (order=2).</summary>
|
||||
Init = 2,
|
||||
|
||||
/// <summary>Program entry - main() (order=3).</summary>
|
||||
Main = 3,
|
||||
|
||||
/// <summary>During termination - DT_FINI, fini_array (order=4).</summary>
|
||||
Fini = 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of synthetic root.
|
||||
@@ -238,9 +269,20 @@ internal static class NativeGraphIdentifiers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes a deterministic root ID.
|
||||
/// Computes a deterministic root ID following CONTRACT-INIT-ROOTS-401 format.
|
||||
/// Format: root:{phase}:{order}:{target_id}
|
||||
/// </summary>
|
||||
public static string ComputeRootId(string targetId, NativeRootType rootType, int order)
|
||||
public static string ComputeRootId(NativeRootPhase phase, int order, string targetId)
|
||||
{
|
||||
var phaseName = phase.ToString().ToLowerInvariant();
|
||||
return $"root:{phaseName}:{order}:{targetId}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes a deterministic root ID (legacy overload for backwards compatibility).
|
||||
/// </summary>
|
||||
[Obsolete("Use ComputeRootId(NativeRootPhase, int, string) for CONTRACT-INIT-ROOTS-401 compliance")]
|
||||
public static string ComputeRootIdLegacy(string targetId, NativeRootType rootType, int order)
|
||||
{
|
||||
var input = $"{targetId}:{rootType}:{order}";
|
||||
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(input));
|
||||
|
||||
Reference in New Issue
Block a user