mirror of
https://github.com/morluto/rea.git
synced 2026-11-11 01:13:39 +00:00
* fix(native)!: report NativeAOT failures as reason codes PeImage admission failures and parser recoveries used to publish Error.message as NativeAotReport.reason. The report is now a union on status, and reason is a typed code with the fields that code needs. Complete reports keep reason null and a located header. Partial and not_applicable reports carry a code. Caller budget mistakes throw AnalysisInputError or AnalysisResourceConstraintError with a diagnostics code instead of a bare Error. * fix(native): keep out-of-domain hydration pointers partial An inline pointer outside the unsigned 64-bit domain made writeBigUInt64LE throw RangeError, and the hydration catch rethrew it instead of recording a partial report. Those targets are now an admission detail. The load-image summary schema still accepts the optional Ghidra extension's string reason. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
125 lines
5.2 KiB
TypeScript
125 lines
5.2 KiB
TypeScript
import { z } from "zod";
|
|
import { nativeAotReasonSchema } from "./nativeAotReason.js";
|
|
|
|
const address = z.string().regex(/^0x[0-9a-f]+$/u);
|
|
const relatedType = z.strictObject({ address, type: z.string().nullable() });
|
|
|
|
/** Runtime-format metadata recovered in an analysis image, with explicit inference boundaries. */
|
|
export const nativeMetadataRecoverySchema = z.strictObject({
|
|
format: z.literal("dotnet-nativeaot"),
|
|
/** Identifies parser-only facts without claiming Ghidra defined a DataType. */
|
|
source: z.enum(["analysis-database", "read-only-derived-overlay"]).optional(),
|
|
status: z.enum(["complete", "partial"]),
|
|
header_address: address,
|
|
format_major: z.int().nonnegative(),
|
|
format_minor: z.int().nonnegative(),
|
|
method_table_address: address,
|
|
name_origin: z.enum(["generated", "inferred"]),
|
|
original_name: z.null(),
|
|
base_size_bytes: z.int().nonnegative(),
|
|
related_type: relatedType.nullable(),
|
|
interfaces: z.array(relatedType),
|
|
virtual_slots: z.array(
|
|
z.strictObject({
|
|
slot: z.int().nonnegative(),
|
|
slot_address: address,
|
|
target_address: address.nullable(),
|
|
procedure_name: z.string().nullable(),
|
|
basis: z.literal("method-table-pointer"),
|
|
}),
|
|
),
|
|
derived_memory: z
|
|
.strictObject({
|
|
address,
|
|
size_bytes: z.int().nonnegative(),
|
|
sha256: z.string().regex(/^[a-f0-9]{64}$/u),
|
|
file_offset: z.null(),
|
|
})
|
|
.nullable(),
|
|
truncated: z.boolean().optional(),
|
|
virtual_slots_omitted: z.int().nonnegative().optional(),
|
|
interfaces_omitted: z.int().nonnegative().optional(),
|
|
output_budget_bytes: z.int().nonnegative().optional(),
|
|
diagnostics: z.array(z.string()),
|
|
limitations: z.array(z.string()),
|
|
});
|
|
export type NativeMetadataRecovery = z.infer<
|
|
typeof nativeMetadataRecoverySchema
|
|
>;
|
|
|
|
/** Discover a recovered runtime format and reusable type identities from the loaded image. */
|
|
export const nativeMetadataRecoverySummarySchema = z.strictObject({
|
|
format: z.literal("dotnet-nativeaot"),
|
|
analysis_mode: z.literal("read-only-derived-overlay").optional(),
|
|
status: z.enum(["complete", "partial", "not_applicable"]),
|
|
// The read-only parser publishes a code. The optional Ghidra extension
|
|
// still sends the historical string on not_applicable, unsupported, and
|
|
// failed image summaries. Both shapes remain valid at this boundary.
|
|
reason: z.union([nativeAotReasonSchema, z.string(), z.null()]),
|
|
analysis_artifact_sha256: z.string().regex(/^[a-f0-9]{64}$/u),
|
|
header_address: address.nullable(),
|
|
discovery: z.enum(["symbol", "signature-heuristic"]).nullable(),
|
|
format_major: z.int().nonnegative().nullable(),
|
|
format_minor: z.int().nonnegative().nullable(),
|
|
method_tables: z.int().nonnegative(),
|
|
types: z.array(relatedType),
|
|
frozen_strings: z
|
|
.array(z.strictObject({ address, value: z.string() }))
|
|
.optional(),
|
|
truncated: z.boolean().optional(),
|
|
types_omitted: z.int().nonnegative().optional(),
|
|
frozen_strings_omitted: z.int().nonnegative().optional(),
|
|
output_budget_bytes: z.int().nonnegative().optional(),
|
|
derived_overlay: z
|
|
.strictObject({
|
|
address,
|
|
size_bytes: z.int().nonnegative(),
|
|
sha256: z.string().regex(/^[a-f0-9]{64}$/u),
|
|
})
|
|
.nullable()
|
|
.optional(),
|
|
derived_memory: nativeMetadataRecoverySchema.shape.derived_memory,
|
|
coverage: z
|
|
.strictObject({
|
|
frozen_object_candidates: z.int().nonnegative().optional(),
|
|
frozen_objects_annotated: z.int().nonnegative().optional(),
|
|
pointer_candidates_examined: z.int().nonnegative().optional(),
|
|
pointer_slots_examined: z.int().nonnegative().optional(),
|
|
scan_bytes_examined: z.int().nonnegative().optional(),
|
|
scan_bytes_omitted: z.int().nonnegative().optional(),
|
|
rtr_signature_scan_bytes_examined: z.int().nonnegative().optional(),
|
|
rtr_signature_scan_bytes_omitted: z.int().nonnegative().optional(),
|
|
method_table_validation_items_examined: z.int().nonnegative().optional(),
|
|
work_units_examined: z.int().nonnegative().optional(),
|
|
method_tables_recovered: z.int().nonnegative().optional(),
|
|
frozen_string_candidates: z.int().nonnegative().optional(),
|
|
frozen_scan_bytes_examined: z.int().nonnegative().optional(),
|
|
frozen_scan_bytes_omitted: z.int().nonnegative().optional(),
|
|
frozen_string_data_bytes_examined: z.int().nonnegative().optional(),
|
|
source_bytes_examined: z.int().nonnegative().optional(),
|
|
source_bytes_omitted: z.int().nonnegative().optional(),
|
|
source_byte_budget_bytes: z.int().nonnegative().optional(),
|
|
work_budget_units: z.int().nonnegative().optional(),
|
|
working_memory_budget_bytes: z.int().nonnegative().optional(),
|
|
working_memory_bytes_peak: z.int().nonnegative().optional(),
|
|
truncation_reason: z
|
|
.enum([
|
|
"source-byte-budget",
|
|
"work-unit-budget",
|
|
"working-memory-budget",
|
|
"response-budget",
|
|
])
|
|
.optional(),
|
|
basis: z.enum([
|
|
"rehydrated-pointer-candidates-and-committed-instance-types",
|
|
"raw-image-pointer-scan",
|
|
"raw-image-and-rehydrated-pointer-scan",
|
|
"unsupported-layout",
|
|
"no-rtr-header",
|
|
]),
|
|
})
|
|
.nullable(),
|
|
diagnostics: z.array(z.string()),
|
|
limitations: z.array(z.string()),
|
|
});
|