Files
reverse-engineering-anything/src/application/XrefsAddressResolution.ts
T
morluto 2826592759 refactor(application): build application cancellations with a required reason (#10574)
* refactor(application): build application cancellations with a required reason

Migrate every AnalysisCancelledError construction under src/application
to cancelledBy and lower the guard baseline from 671 to 442.

Shutdown refusals in BinarySession report OwnerCancellation.ownerClosed
when the caller did not abort, instead of an undefined reason.
ReverseEngineeringService and DesktopBuildOwnedWork close their work
with the typed owner reason. SharedStartupAttempt returns the departing
caller's reason with a cancelled wait. One shared isAborted predicate
replaces eleven local copies and narrows a checked signal for
cancelledBy.

* refactor(desktop): drop an unused cancellation import from desktop capture state
2026-11-15 18:38:24 +08:00

110 lines
3.8 KiB
TypeScript

import { permitsCapabilityFallback } from "./CapabilityFallback.js";
import { listNamesFact } from "../domain/native/nativeOperationFacts.js";
import { executeFact } from "./AnalysisOperationFacts.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import {
AnalysisInputError,
AnalysisOutputError,
cancelledBy,
} from "../domain/analysisErrorCore.js";
import { err, ok, type Result } from "../domain/result.js";
import type { AnalysisOperationPort } from "./AnalysisProvider.js";
import { resolveProcedureAddress } from "./ProcedureAddressResolution.js";
/** Resolve an exact symbol after the provider rejects the caller address format. */
export const resolveXrefsAddress = async (
analysis: AnalysisOperationPort,
selector: string,
signal: AbortSignal,
): Promise<Result<string, AnalysisError>> => {
const named = await resolveXrefsName(analysis, selector, signal);
if (!named.ok) return named;
return named.value !== null
? ok(named.value)
: err(
new AnalysisInputError(
"xrefs",
{
conformsToInputContract: true,
remediationAction:
"For a function, use rea search --kind procedures to find an analyzed address. For exports, inspect-macho (Mach-O) or inspect-native-exports (PE/ELF) may help; exports can omit local symbols and use different address coordinates. Verify the address in the selected provider, then retry xrefs.",
},
[
{
path: ["address"],
reason: "invalid_value",
message: `Unknown analyzed symbol name ${JSON.stringify(selector)}. Use an exact analyzed name or a hexadecimal address.`,
},
],
),
);
};
/** Exact name resolution has one ambiguity owner for enhanced tools and CLI fallback. */
export const resolveXrefsName = async (
analysis: AnalysisOperationPort,
selector: string,
signal?: AbortSignal,
operation: "xrefs" | "find_xrefs_to_name" = "xrefs",
): Promise<Result<string | null, AnalysisError>> => {
if (signal?.aborted) return err(cancelledBy(operation, signal));
const inventory = await executeFact(
analysis,
listNamesFact,
{},
signal === undefined ? {} : { signal },
);
if (!inventory.ok) {
if (
operation === "xrefs" &&
permitsCapabilityFallback(inventory.error) &&
inventory.error.operation === "list_names"
)
return resolveProcedureAddress(
async (operation, parameters, signal) => {
const result = await analysis.execute(
operation,
parameters,
signal === undefined ? {} : { signal },
);
return result.ok ? ok(result.value.result) : result;
},
selector,
signal,
);
return inventory;
}
if (signal?.aborted) return err(cancelledBy(operation, signal));
const addresses = new Set<string>();
for (const [index, row] of inventory.value.fact.entries()) {
// An empty address cannot be passed back to xrefs.
if (row.address.length === 0)
return err(
new AnalysisOutputError(
"list_names",
`Invalid symbol inventory entry at index ${index}`,
),
);
if (row.value === selector) addresses.add(row.address);
}
const [address] = addresses;
if (addresses.size <= 1) return ok(address ?? null);
return err(
new AnalysisInputError(
operation,
{
conformsToInputContract: true,
remediationAction:
"Select an exact address from the candidates and call xrefs with that address.",
},
[
{
path: [operation === "xrefs" ? "address" : "name"],
reason: "invalid_value",
message: `Analyzed symbol name ${JSON.stringify(selector)} is ambiguous at ${[...addresses].sort().join(", ")}. Select an exact address.`,
},
],
),
);
};