namespace StellaOps.Signals.Services;
///
/// Symbol canonicalization service interface.
/// Sprint: SPRINT_20251226_010_SIGNALS_runtime_stack
/// Task: STACK-06
///
/// Resolves program counter addresses to canonical (Build-ID, function, offset) tuples.
///
public interface ISymbolCanonicalizationService
{
///
/// Resolves a program counter address to a canonical symbol.
///
/// The program counter address.
/// The ELF Build-ID of the binary.
/// Optional path to the binary for symbol lookup.
/// Cancellation token.
/// The resolved symbol, or null if resolution failed.
Task ResolveAsync(
ulong address,
string? buildId,
string? binaryPath = null,
CancellationToken cancellationToken = default);
///
/// Resolves multiple addresses in batch for efficiency.
///
Task> ResolveBatchAsync(
IReadOnlyList requests,
CancellationToken cancellationToken = default);
///
/// Resolves a Java frame using JVMTI metadata.
///
Task ResolveJavaFrameAsync(
ulong address,
JavaFrameMetadata metadata,
CancellationToken cancellationToken = default);
///
/// Resolves a .NET frame using DAC (Data Access Component).
///
Task ResolveDotNetFrameAsync(
ulong address,
DotNetFrameMetadata metadata,
CancellationToken cancellationToken = default);
///
/// Resolves a Python frame using interpreter symbols.
///
Task ResolvePythonFrameAsync(
ulong address,
PythonFrameMetadata metadata,
CancellationToken cancellationToken = default);
///
/// Checks if a Build-ID is in the local symbol cache.
///
Task IsInCacheAsync(string buildId, CancellationToken cancellationToken = default);
///
/// Adds symbols for a Build-ID to the cache.
///
Task CacheSymbolsAsync(
string buildId,
IReadOnlyList symbols,
CancellationToken cancellationToken = default);
}
///
/// Request for symbol resolution.
///
public sealed record SymbolResolutionRequest
{
///
/// Program counter address.
///
public required ulong Address { get; init; }
///
/// ELF Build-ID of the binary.
///
public string? BuildId { get; init; }
///
/// Path to the binary file.
///
public string? BinaryPath { get; init; }
///
/// Runtime type hint for managed runtimes.
///
public RuntimeType RuntimeType { get; init; } = RuntimeType.Native;
}
///
/// Runtime type for symbol resolution hints.
///
public enum RuntimeType
{
///
/// Native code (C, C++, Rust, Go, etc.).
///
Native,
///
/// Java Virtual Machine.
///
Java,
///
/// .NET Common Language Runtime.
///
DotNet,
///
/// Python interpreter.
///
Python,
///
/// Node.js / V8.
///
NodeJs,
///
/// Ruby interpreter.
///
Ruby,
}
///
/// Canonical symbol representation.
///
public sealed record CanonicalSymbol
{
///
/// Original address that was resolved.
///
public required ulong Address { get; init; }
///
/// ELF Build-ID of the containing binary.
///
public required string BuildId { get; init; }
///
/// Demangled function name.
///
public required string FunctionName { get; init; }
///
/// Offset within the function.
///
public required ulong Offset { get; init; }
///
/// Module or binary name.
///
public string? ModuleName { get; init; }
///
/// Source file path (if debug info available).
///
public string? SourceFile { get; init; }
///
/// Source line number.
///
public int? SourceLine { get; init; }
///
/// Whether this symbol is from a trusted source.
///
public bool IsTrusted { get; init; }
///
/// Resolution method used.
///
public SymbolResolutionMethod ResolutionMethod { get; init; }
///
/// Returns the canonical string format.
///
public string ToCanonicalString()
{
return $"{BuildId[..Math.Min(16, BuildId.Length)]}:{FunctionName}+0x{Offset:x}";
}
///
/// Parses a canonical string format.
///
public static CanonicalSymbol? Parse(string canonical)
{
if (string.IsNullOrWhiteSpace(canonical))
return null;
// Format: "buildid:function+0xoffset"
var colonIdx = canonical.IndexOf(':');
if (colonIdx < 0)
return null;
var buildId = canonical[..colonIdx];
var rest = canonical[(colonIdx + 1)..];
var plusIdx = rest.LastIndexOf('+');
if (plusIdx < 0)
return null;
var functionName = rest[..plusIdx];
var offsetStr = rest[(plusIdx + 1)..];
if (!offsetStr.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
return null;
if (!ulong.TryParse(offsetStr[2..], System.Globalization.NumberStyles.HexNumber, null, out var offset))
return null;
return new CanonicalSymbol
{
Address = 0, // Not recoverable from canonical string
BuildId = buildId,
FunctionName = functionName,
Offset = offset,
ResolutionMethod = SymbolResolutionMethod.Parsed,
};
}
}
///
/// Method used to resolve the symbol.
///
public enum SymbolResolutionMethod
{
///
/// Resolved from ELF symbol table.
///
ElfSymtab,
///
/// Resolved from DWARF debug info.
///
DwarfDebugInfo,
///
/// Resolved from local symbol cache.
///
LocalCache,
///
/// Resolved from debuginfod server.
///
Debuginfod,
///
/// Resolved from JIT metadata (Java/V8/etc).
///
JitMetadata,
///
/// Resolved from runtime-specific mechanism.
///
RuntimeSpecific,
///
/// Parsed from canonical string format.
///
Parsed,
///
/// Could not resolve, using address only.
///
Unresolved,
}
///
/// Symbol entry for cache storage.
///
public sealed record SymbolEntry
{
///
/// Start address of the symbol.
///
public required ulong StartAddress { get; init; }
///
/// Size of the symbol in bytes.
///
public required ulong Size { get; init; }
///
/// Symbol name (demangled).
///
public required string Name { get; init; }
///
/// Symbol type.
///
public SymbolType Type { get; init; } = SymbolType.Function;
}
///
/// Type of symbol.
///
public enum SymbolType
{
Function,
Object,
Unknown,
}
///
/// Metadata for Java frame resolution.
///
public sealed record JavaFrameMetadata
{
///
/// Class name.
///
public string? ClassName { get; init; }
///
/// Method name.
///
public string? MethodName { get; init; }
///
/// Method signature.
///
public string? Signature { get; init; }
///
/// Bytecode index.
///
public int? BytecodeIndex { get; init; }
///
/// Whether this is a JIT-compiled frame.
///
public bool IsJit { get; init; }
}
///
/// Metadata for .NET frame resolution.
///
public sealed record DotNetFrameMetadata
{
///
/// Type name.
///
public string? TypeName { get; init; }
///
/// Method name.
///
public string? MethodName { get; init; }
///
/// Method token.
///
public uint? MethodToken { get; init; }
///
/// IL offset.
///
public int? IlOffset { get; init; }
///
/// Assembly name.
///
public string? AssemblyName { get; init; }
}
///
/// Metadata for Python frame resolution.
///
public sealed record PythonFrameMetadata
{
///
/// Module name.
///
public string? ModuleName { get; init; }
///
/// Function name.
///
public string? FunctionName { get; init; }
///
/// Source file path.
///
public string? SourceFile { get; init; }
///
/// Line number.
///
public int? LineNumber { get; init; }
///
/// Python version.
///
public string? PythonVersion { get; init; }
}