ITERATE-2.V: scheduler priority aging closes 18-day AUDIT-049 wedge
Priority aging in xenia-cpu/scheduler.rs:pick_runnable
(effective_priority = base + age_bonus(now_round - last_run_round),
capped at +31, AGING_ROUNDS_PER_BONUS=1). Strict-priority was parking
priority=0 threads behind CPU-bound priority=15 audio mixer
(sub_824D1328 guest spinwait at PC=0x824d1404 on CPU5). Aging
eventually picks the starved thread, breaking the producer-consumer
cycle that caused 5-tid wedge at PC=0x824ac578 since AUDIT-049 (10 May).
Cascade observed: tid=13 clean exit; events 121K -> 13M (107x); last
host_ns 767ms -> 51,011ms (66x); 8 new threads spawn; VdSwap 1 -> 2.
Complete two-day iterate sequence (2026-05-27 -> 2026-05-28):
- 2.F: VdSwap drain timeout 900ms -> 1ms (xenia-gpu/handle.rs); 876x
perf win on VdSwap kernel callback
- 2.H: vA0000000 physical heap bucket added (state.rs, exports.rs);
ctx_ptrs now in 0xA0000000-0xBFFFFFFF range matching canary
- 2.L: Phase-A diff harness categorized [return_value mismatch],
[status mismatch], [args_resolved.path mismatch] tags
(tools/diff-events/diff_events.py); closes reading-error #41
(silent test-harness state leak invalidating trace diffs)
- 2.M: always-on exit-thread-state.json sibling to Phase-A JSONL
(event_log.rs + xenia-app/main.rs); closes reading-error #42
(Phase-A blind to blocked-forever waits)
- 2.Q: signal.match kernel instrumentation in NtSetEvent /
NtReleaseSemaphore / KeSetEvent / KeReleaseSemaphore
(exports.rs); emits target_handle + waiter_count + waiter_tids
- 2.T: wake.requested kernel instrumentation in wake_eligible_waiters
(exports.rs); emits target_tid + transition + new_state
- 2.V: scheduler priority aging (xenia-cpu/scheduler.rs) [keystone]
Plus accumulated WIP from earlier May (contention_manifest,
phase_b_snapshot, xam/xaudio enhancements, analysis db, xex loader,
xenia-app main loop, etc.). Audit-runs/ artifacts remain untracked
per project convention.
Tests: 300 xenia-cpu / 227 xenia-kernel / 5 xenia-app / 19 xenia-path
/ 30+ smaller suites -- all PASS, 0 regressions. Determinism preserved
(2x cold runs bit-identical at 13,003,881 events post-2.V).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -897,17 +897,12 @@ fn insert_functions(
|
||||
func_analysis: &FuncAnalysis,
|
||||
labels: &HashMap<u32, String>,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut stmt = conn.prepare(
|
||||
"INSERT INTO functions
|
||||
(address, name, end_address, frame_size, saved_gprs, is_leaf, is_saverestore,
|
||||
pdata_validated, pdata_length, has_eh)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
||||
)?;
|
||||
let mut app = conn.appender("functions")?;
|
||||
for (&addr, fi) in &func_analysis.functions {
|
||||
let name = labels.get(&addr)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| format!("sub_{addr:08X}"));
|
||||
stmt.execute(params![
|
||||
app.append_row(params![
|
||||
addr as i64,
|
||||
name,
|
||||
fi.end as i64,
|
||||
@@ -920,6 +915,7 @@ fn insert_functions(
|
||||
fi.has_eh,
|
||||
])?;
|
||||
}
|
||||
app.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -930,15 +926,13 @@ fn insert_vtables(
|
||||
_image_base: u32,
|
||||
) -> anyhow::Result<()> {
|
||||
if vtables.is_empty() { return Ok(()); }
|
||||
let mut stmt = conn.prepare(
|
||||
"INSERT INTO vtables
|
||||
(address, length, col_address, class_name, rtti_present, base_classes_json)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
let mut count = 0u64;
|
||||
let mut dedup: HashMap<u32, &crate::vtables::Vtable> = HashMap::new();
|
||||
for v in vtables {
|
||||
stmt.execute(params![
|
||||
dedup.entry(v.address).or_insert(v);
|
||||
}
|
||||
let mut app = conn.appender("vtables")?;
|
||||
for v in dedup.values() {
|
||||
app.append_row(params![
|
||||
v.address as i64,
|
||||
v.length as i64,
|
||||
v.col_address.map(|a| a as i64),
|
||||
@@ -946,8 +940,9 @@ fn insert_vtables(
|
||||
v.rtti_present,
|
||||
v.base_classes_json.as_deref(),
|
||||
])?;
|
||||
count += 1;
|
||||
}
|
||||
app.flush()?;
|
||||
let count = dedup.len() as u64;
|
||||
metrics::counter!("db.rows", "table" => "vtables").increment(count);
|
||||
tracing::info!(rows = count, table = "vtables", "bulk insert complete");
|
||||
Ok(())
|
||||
@@ -960,17 +955,17 @@ fn insert_methods_and_classes(
|
||||
) -> anyhow::Result<()> {
|
||||
if vtables.is_empty() { return Ok(()); }
|
||||
|
||||
// methods rows
|
||||
// methods rows — dedup by (vtable_address, slot), first-write-wins.
|
||||
let methods = crate::vtables::methods_table(vtables, labels);
|
||||
if !methods.is_empty() {
|
||||
let mut stmt = conn.prepare(
|
||||
"INSERT INTO methods
|
||||
(vtable_address, slot, function_address, mangled_name, demangled_name)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
for (vt_addr, slot, fn_addr, mangled, demangled) in &methods {
|
||||
stmt.execute(params![
|
||||
let mut idx: HashMap<(u32, u32), usize> = HashMap::new();
|
||||
for (i, m) in methods.iter().enumerate() {
|
||||
idx.entry((m.0, m.1)).or_insert(i);
|
||||
}
|
||||
let mut app = conn.appender("methods")?;
|
||||
for &i in idx.values() {
|
||||
let (vt_addr, slot, fn_addr, mangled, demangled) = &methods[i];
|
||||
app.append_row(params![
|
||||
*vt_addr as i64,
|
||||
*slot as i64,
|
||||
*fn_addr as i64,
|
||||
@@ -978,29 +973,33 @@ fn insert_methods_and_classes(
|
||||
demangled.as_deref(),
|
||||
])?;
|
||||
}
|
||||
metrics::counter!("db.rows", "table" => "methods").increment(methods.len() as u64);
|
||||
tracing::info!(rows = methods.len(), table = "methods", "bulk insert complete");
|
||||
app.flush()?;
|
||||
let n = idx.len() as u64;
|
||||
metrics::counter!("db.rows", "table" => "methods").increment(n);
|
||||
tracing::info!(rows = n, table = "methods", "bulk insert complete");
|
||||
}
|
||||
|
||||
// classes rows (deduped by class_name, first-detected wins)
|
||||
// classes rows — dedup by class_name, first-detected wins.
|
||||
let classes = crate::vtables::classes_table(vtables);
|
||||
if !classes.is_empty() {
|
||||
let mut stmt = conn.prepare(
|
||||
"INSERT INTO classes
|
||||
(name, vtable_address, rtti_present, base_classes_json)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
for (name, vt_addr, rtti, bases) in &classes {
|
||||
stmt.execute(params![
|
||||
let mut idx: HashMap<&str, usize> = HashMap::new();
|
||||
for (i, c) in classes.iter().enumerate() {
|
||||
idx.entry(c.0.as_str()).or_insert(i);
|
||||
}
|
||||
let mut app = conn.appender("classes")?;
|
||||
for &i in idx.values() {
|
||||
let (name, vt_addr, rtti, bases) = &classes[i];
|
||||
app.append_row(params![
|
||||
name.as_str(),
|
||||
*vt_addr as i64,
|
||||
*rtti,
|
||||
bases.as_deref(),
|
||||
])?;
|
||||
}
|
||||
metrics::counter!("db.rows", "table" => "classes").increment(classes.len() as u64);
|
||||
tracing::info!(rows = classes.len(), table = "classes", "bulk insert complete");
|
||||
app.flush()?;
|
||||
let n = idx.len() as u64;
|
||||
metrics::counter!("db.rows", "table" => "classes").increment(n);
|
||||
tracing::info!(rows = n, table = "classes", "bulk insert complete");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -1011,20 +1010,21 @@ fn insert_strings(
|
||||
strings: &[crate::strings::DetectedString],
|
||||
) -> anyhow::Result<()> {
|
||||
if strings.is_empty() { return Ok(()); }
|
||||
let mut stmt = conn.prepare(
|
||||
"INSERT INTO strings (address, encoding, length, content) VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
let mut count = 0u64;
|
||||
let mut dedup: HashMap<u32, &crate::strings::DetectedString> = HashMap::new();
|
||||
for s in strings {
|
||||
stmt.execute(params![
|
||||
dedup.entry(s.address).or_insert(s);
|
||||
}
|
||||
let mut app = conn.appender("strings")?;
|
||||
for s in dedup.values() {
|
||||
app.append_row(params![
|
||||
s.address as i64,
|
||||
s.encoding,
|
||||
s.length as i64,
|
||||
s.content.as_str(),
|
||||
])?;
|
||||
count += 1;
|
||||
}
|
||||
app.flush()?;
|
||||
let count = dedup.len() as u64;
|
||||
metrics::counter!("db.rows", "table" => "strings").increment(count);
|
||||
tracing::info!(rows = count, table = "strings", "bulk insert complete");
|
||||
Ok(())
|
||||
@@ -1035,31 +1035,17 @@ fn insert_eh_records(
|
||||
records: &[crate::eh_scope::EhFuncInfo],
|
||||
) -> anyhow::Result<()> {
|
||||
if records.is_empty() { return Ok(()); }
|
||||
let mut stmt_fi = conn.prepare(
|
||||
"INSERT INTO eh_funcinfo
|
||||
(address, magic, max_state, p_unwind_map, n_try_blocks,
|
||||
p_try_block_map, n_ip_map_entries, p_ip_to_state_map,
|
||||
p_es_type_list, eh_flags)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
let mut stmt_unwind = conn.prepare(
|
||||
"INSERT INTO eh_unwind_map
|
||||
(funcinfo_address, state_index, to_state, action_pc)
|
||||
VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
let mut stmt_try = conn.prepare(
|
||||
"INSERT INTO eh_try_blocks
|
||||
(funcinfo_address, try_index, try_low, try_high, catch_high,
|
||||
n_catches, p_handler_array)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
let mut n_fi = 0u64;
|
||||
let mut n_unwind = 0u64;
|
||||
let mut n_try = 0u64;
|
||||
for r in records {
|
||||
stmt_fi.execute(params![
|
||||
// Dedup eh_funcinfo by PK (address), first-write-wins.
|
||||
// Within a deduped record, unwind/try entries are uniquely indexed by enumerate.
|
||||
let mut fi_idx: HashMap<u32, usize> = HashMap::new();
|
||||
for (i, r) in records.iter().enumerate() {
|
||||
fi_idx.entry(r.address).or_insert(i);
|
||||
}
|
||||
|
||||
let mut app_fi = conn.appender("eh_funcinfo")?;
|
||||
for &i in fi_idx.values() {
|
||||
let r = &records[i];
|
||||
app_fi.append_row(params![
|
||||
r.address as i64, r.magic as i64, r.max_state as i64,
|
||||
r.p_unwind_map as i64, r.n_try_blocks as i64,
|
||||
r.p_try_block_map as i64, r.n_ip_map_entries as i64,
|
||||
@@ -1067,22 +1053,38 @@ fn insert_eh_records(
|
||||
r.p_es_type_list.map(|p| p as i64),
|
||||
r.eh_flags.map(|f| f as i64),
|
||||
])?;
|
||||
n_fi += 1;
|
||||
for (i, e) in r.unwind_map.iter().enumerate() {
|
||||
stmt_unwind.execute(params![
|
||||
r.address as i64, i as i64, e.to_state as i64, e.action_pc as i64,
|
||||
}
|
||||
app_fi.flush()?;
|
||||
let n_fi = fi_idx.len() as u64;
|
||||
|
||||
let mut app_unwind = conn.appender("eh_unwind_map")?;
|
||||
let mut n_unwind = 0u64;
|
||||
for &i in fi_idx.values() {
|
||||
let r = &records[i];
|
||||
for (j, e) in r.unwind_map.iter().enumerate() {
|
||||
app_unwind.append_row(params![
|
||||
r.address as i64, j as i64, e.to_state as i64, e.action_pc as i64,
|
||||
])?;
|
||||
n_unwind += 1;
|
||||
}
|
||||
for (i, t) in r.try_blocks.iter().enumerate() {
|
||||
stmt_try.execute(params![
|
||||
r.address as i64, i as i64,
|
||||
}
|
||||
app_unwind.flush()?;
|
||||
|
||||
let mut app_try = conn.appender("eh_try_blocks")?;
|
||||
let mut n_try = 0u64;
|
||||
for &i in fi_idx.values() {
|
||||
let r = &records[i];
|
||||
for (j, t) in r.try_blocks.iter().enumerate() {
|
||||
app_try.append_row(params![
|
||||
r.address as i64, j as i64,
|
||||
t.try_low as i64, t.try_high as i64, t.catch_high as i64,
|
||||
t.n_catches as i64, t.p_handler_array as i64,
|
||||
])?;
|
||||
n_try += 1;
|
||||
}
|
||||
}
|
||||
app_try.flush()?;
|
||||
|
||||
metrics::counter!("db.rows", "table" => "eh_funcinfo").increment(n_fi);
|
||||
metrics::counter!("db.rows", "table" => "eh_unwind_map").increment(n_unwind);
|
||||
metrics::counter!("db.rows", "table" => "eh_try_blocks").increment(n_try);
|
||||
@@ -1097,54 +1099,55 @@ fn insert_typed_ind_dispatch(
|
||||
conn: &Connection,
|
||||
t: &crate::ind_dispatch_typed::TypedIndirectResult,
|
||||
) -> anyhow::Result<()> {
|
||||
// Dedupe by PK before appending: the Appender writes directly to columnar
|
||||
// storage and does not enforce primary keys, so duplicates here would
|
||||
// surface as PK violations at flush. First-write-wins matches the previous
|
||||
// `ON CONFLICT DO NOTHING` behaviour.
|
||||
if !t.dispatches.is_empty() {
|
||||
let mut stmt_site = conn.prepare(
|
||||
"INSERT INTO indirect_dispatch_sites
|
||||
(dispatch_pc, vptr_offset, slot, candidate_count)
|
||||
VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
let mut stmt_cand = conn.prepare(
|
||||
"INSERT INTO indirect_dispatch_candidates
|
||||
(dispatch_pc, vtable_address, method_address)
|
||||
VALUES (?, ?, ?) ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
let mut n_sites = 0u64;
|
||||
let mut n_cand = 0u64;
|
||||
let mut sites: HashMap<u32, (u32, u32, usize)> = HashMap::new();
|
||||
let mut cands: HashMap<(u32, u32), u32> = HashMap::new();
|
||||
for d in &t.dispatches {
|
||||
stmt_site.execute(params![
|
||||
d.dispatch_pc as i64,
|
||||
d.vptr_offset as i64,
|
||||
d.slot as i64,
|
||||
d.candidate_vtables.len() as i64,
|
||||
])?;
|
||||
n_sites += 1;
|
||||
sites.entry(d.dispatch_pc)
|
||||
.or_insert((d.vptr_offset, d.slot, d.candidate_vtables.len()));
|
||||
for (vt, m) in d.candidate_vtables.iter().zip(d.method_pcs.iter()) {
|
||||
stmt_cand.execute(params![
|
||||
d.dispatch_pc as i64, *vt as i64, *m as i64,
|
||||
])?;
|
||||
n_cand += 1;
|
||||
cands.entry((d.dispatch_pc, *vt)).or_insert(*m);
|
||||
}
|
||||
}
|
||||
|
||||
let mut app_sites = conn.appender("indirect_dispatch_sites")?;
|
||||
for (pc, (off, slot, count)) in &sites {
|
||||
app_sites.append_row(params![
|
||||
*pc as i64, *off as i64, *slot as i64, *count as i64,
|
||||
])?;
|
||||
}
|
||||
app_sites.flush()?;
|
||||
|
||||
let mut app_cand = conn.appender("indirect_dispatch_candidates")?;
|
||||
for ((pc, vt), m) in &cands {
|
||||
app_cand.append_row(params![*pc as i64, *vt as i64, *m as i64])?;
|
||||
}
|
||||
app_cand.flush()?;
|
||||
|
||||
let n_sites = sites.len() as u64;
|
||||
let n_cand = cands.len() as u64;
|
||||
metrics::counter!("db.rows", "table" => "indirect_dispatch_sites").increment(n_sites);
|
||||
metrics::counter!("db.rows", "table" => "indirect_dispatch_candidates").increment(n_cand);
|
||||
tracing::info!(sites = n_sites, candidates = n_cand, "typed indirect-dispatch insert complete");
|
||||
}
|
||||
if !t.vptr_writes.is_empty() {
|
||||
let mut stmt = conn.prepare(
|
||||
"INSERT INTO vptr_writes
|
||||
(writer_pc, vtable_address, vptr_offset, writer_function)
|
||||
VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
let mut n = 0u64;
|
||||
let mut writes: HashMap<(u32, u32, u32), u32> = HashMap::new();
|
||||
for w in &t.vptr_writes {
|
||||
stmt.execute(params![
|
||||
w.writer_pc as i64,
|
||||
w.vtable_addr as i64,
|
||||
w.vptr_offset as i64,
|
||||
w.writer_function as i64,
|
||||
])?;
|
||||
n += 1;
|
||||
writes.entry((w.writer_pc, w.vtable_addr, w.vptr_offset))
|
||||
.or_insert(w.writer_function);
|
||||
}
|
||||
let mut app = conn.appender("vptr_writes")?;
|
||||
for ((wpc, vt, off), wf) in &writes {
|
||||
app.append_row(params![
|
||||
*wpc as i64, *vt as i64, *off as i64, *wf as i64,
|
||||
])?;
|
||||
}
|
||||
app.flush()?;
|
||||
let n = writes.len() as u64;
|
||||
metrics::counter!("db.rows", "table" => "vptr_writes").increment(n);
|
||||
tracing::info!(rows = n, "vptr_writes insert complete");
|
||||
}
|
||||
@@ -1156,26 +1159,31 @@ fn insert_funcptr_arrays(
|
||||
arrays: &[crate::funcptr_arrays::FuncPtrArray],
|
||||
) -> anyhow::Result<()> {
|
||||
if arrays.is_empty() { return Ok(()); }
|
||||
let mut stmt_arr = conn.prepare(
|
||||
"INSERT INTO function_pointer_arrays (address, length, kind) VALUES (?, ?, ?)
|
||||
ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
let mut stmt_ent = conn.prepare(
|
||||
"INSERT INTO function_pointer_array_entries (array_address, slot, function_address)
|
||||
VALUES (?, ?, ?) ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
let mut n_arr = 0u64;
|
||||
// Dedup arrays by PK (address), first-write-wins.
|
||||
let mut idx: HashMap<u32, usize> = HashMap::new();
|
||||
for (i, a) in arrays.iter().enumerate() {
|
||||
idx.entry(a.address).or_insert(i);
|
||||
}
|
||||
|
||||
let mut app_arr = conn.appender("function_pointer_arrays")?;
|
||||
for &i in idx.values() {
|
||||
let a = &arrays[i];
|
||||
app_arr.append_row(params![a.address as i64, a.length as i64, a.kind])?;
|
||||
}
|
||||
app_arr.flush()?;
|
||||
let n_arr = idx.len() as u64;
|
||||
|
||||
let mut app_ent = conn.appender("function_pointer_array_entries")?;
|
||||
let mut n_ent = 0u64;
|
||||
for a in arrays {
|
||||
let inserted = stmt_arr.execute(params![
|
||||
a.address as i64, a.length as i64, a.kind,
|
||||
])?;
|
||||
if inserted > 0 { n_arr += 1; }
|
||||
for (i, &fn_va) in a.entries.iter().enumerate() {
|
||||
stmt_ent.execute(params![a.address as i64, i as i64, fn_va as i64])?;
|
||||
for &i in idx.values() {
|
||||
let a = &arrays[i];
|
||||
for (slot, &fn_va) in a.entries.iter().enumerate() {
|
||||
app_ent.append_row(params![a.address as i64, slot as i64, fn_va as i64])?;
|
||||
n_ent += 1;
|
||||
}
|
||||
}
|
||||
app_ent.flush()?;
|
||||
|
||||
metrics::counter!("db.rows", "table" => "function_pointer_arrays").increment(n_arr);
|
||||
metrics::counter!("db.rows", "table" => "function_pointer_array_entries").increment(n_ent);
|
||||
tracing::info!(arrays = n_arr, entries = n_ent, "function-pointer arrays insert complete");
|
||||
@@ -1187,13 +1195,8 @@ fn insert_demangled_from_labels(
|
||||
labels: &HashMap<u32, String>,
|
||||
import_libraries: &[xenia_xex::header::ImportLibrary],
|
||||
) -> anyhow::Result<()> {
|
||||
let mut stmt = conn.prepare(
|
||||
"INSERT INTO demangled_names
|
||||
(address, mangled, raw_demangled, namespace_path, class_name,
|
||||
method_name, params_signature)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)"
|
||||
)?;
|
||||
|
||||
// demangled_names has no PK — straight append, no dedup needed.
|
||||
let mut app = conn.appender("demangled_names")?;
|
||||
let mut count = 0u64;
|
||||
|
||||
for (&addr, name) in labels {
|
||||
@@ -1206,7 +1209,7 @@ fn insert_demangled_from_labels(
|
||||
continue;
|
||||
}
|
||||
if let Some(d) = crate::demangle::demangle(name) {
|
||||
stmt.execute(params![
|
||||
app.append_row(params![
|
||||
addr as i64,
|
||||
d.mangled,
|
||||
d.raw_demangled,
|
||||
@@ -1226,7 +1229,7 @@ fn insert_demangled_from_labels(
|
||||
if let Some(name) = resolved
|
||||
&& let Some(d) = crate::demangle::demangle(name)
|
||||
{
|
||||
stmt.execute(params![
|
||||
app.append_row(params![
|
||||
imp.address as i64,
|
||||
d.mangled,
|
||||
d.raw_demangled,
|
||||
@@ -1240,6 +1243,7 @@ fn insert_demangled_from_labels(
|
||||
}
|
||||
}
|
||||
|
||||
app.flush()?;
|
||||
metrics::counter!("db.rows", "table" => "demangled_names").increment(count);
|
||||
tracing::info!(rows = count, table = "demangled_names", "demangler complete");
|
||||
Ok(())
|
||||
@@ -1252,14 +1256,15 @@ fn insert_pdata_entries(
|
||||
if entries.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut stmt = conn.prepare(
|
||||
"INSERT INTO pdata_entries
|
||||
(begin_address, end_address, function_length, prolog_length, flags)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
for e in entries {
|
||||
stmt.execute(params![
|
||||
// Dedup by PK (begin_address), first-write-wins.
|
||||
let mut idx: HashMap<u32, usize> = HashMap::new();
|
||||
for (i, e) in entries.iter().enumerate() {
|
||||
idx.entry(e.begin_address).or_insert(i);
|
||||
}
|
||||
let mut app = conn.appender("pdata_entries")?;
|
||||
for &i in idx.values() {
|
||||
let e = &entries[i];
|
||||
app.append_row(params![
|
||||
e.begin_address as i64,
|
||||
e.end_address() as i64,
|
||||
e.function_length as i64,
|
||||
@@ -1267,6 +1272,7 @@ fn insert_pdata_entries(
|
||||
e.flags as i64,
|
||||
])?;
|
||||
}
|
||||
app.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1274,9 +1280,8 @@ fn insert_labels(
|
||||
conn: &Connection,
|
||||
labels: &HashMap<u32, String>,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut stmt = conn.prepare(
|
||||
"INSERT INTO labels (address, name, kind) VALUES (?, ?, ?) ON CONFLICT DO NOTHING"
|
||||
)?;
|
||||
// Source is a HashMap so addresses are unique by construction — no dedup needed.
|
||||
let mut app = conn.appender("labels")?;
|
||||
for (&addr, name) in labels {
|
||||
let kind = if name.starts_with("sub_") || name == "entry_point" {
|
||||
"function"
|
||||
@@ -1291,8 +1296,9 @@ fn insert_labels(
|
||||
} else {
|
||||
"other"
|
||||
};
|
||||
stmt.execute(params![addr as i64, name, kind])?;
|
||||
app.append_row(params![addr as i64, name, kind])?;
|
||||
}
|
||||
app.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user