Files
envi-code/tools/resolve_rva.ps1
T
company-desktop 7038a98441 diag: 用 PDB 解析栈帧,定位到 AecDbEwPipeBase::copyFrom 里的多余序列化
上一版只给了"模块+RVA"的栈,我据此先后推断成
AecDbCurveBase::subGetTransformedCopy 和 AecDbEntityCommon::base_DeepClone,两者都是错的
(用户在那里下断点不命中;新加的 PerfTraceMark 打点也没有触发)。本次用符号解析定死。

本次改动:
- 新增 inc/PerfTraceMark.h:inline 的"某函数被调用过"打点,Debug 且 AEC_WRITEBACK_TRACE=1
  才生效。AecRxBase.arx 不链接 CoreLibrary(静态库只被 CoreCommand 链接),拿不到 SectionPerf,
  所以做成 header-only。
- 在 5 个候选入口打点:AecDbCurveBase::subGetTransformedCopy / subDeepClone、
  AecDbEntityBase::subDeepClone、AecDbEntityCommon::base_DeepClone、CKTCadUtility::CloneObject。
  跑一次开图,5 个都没触发 —— 这些候选被排除。
- 新增 tools/resolve_rva.ps1:用 dbghelp 的 SymLoadModuleEx / SymFromAddr 配本地 PDB,
  把"模块+RVA"解析成函数名。Windows 没有自带 symbolizer,这个脚本很轻,可反复用。

解析结果(CoreCommand.arx):
  0x58f051  AecDbEwPipeBase::copyFrom+0x41
  0x7e1300  AecDbZLineStair::DrawGuarBar3d+0x2c0
  0x7e09d0  AecDbZLineStair::DrawSteep3d+0xbe0
  0x7ddcef  AecDbZLineStair::Draw3d+0x34f

真实成因:Z 型楼梯画护栏(DrawGuarBar3d)时 copyFrom 一份管道实体,
而 AecDbEwPipeBase::copyFrom 用通用的 CopyObject(inc/AecDbEntityCommon.h:331)
做"整实体 dwgOutFields/dwgInFields 往返"来拷字段,于是截面被写成临时 SAT 文件再读回来。

而且这次序列化是多余的:copyFrom 随后把所有字段又用内存级方式拷了一遍
(曲线 clone/copyFrom、截面 clone/copyFrom、XData CopyFrom、m_arUserInfs append、
标志位/图层/线型/Breaks 逐项赋值),WriteUserInterface 写的也只是 m_arUserInfs。
所以最小修改是把那句 CopyObject 去掉,并补上源为 NULL 时清空目标的分支
(目前这个"清空"是 CopyObject 顺带完成的)。

本次只做定位与记录(分析写进 pipe-section-region-performance-plan.md 并纠正了上一版的误判),
不改 copyFrom 的行为——它影响所有管系实体的复制粘贴/块内拷贝,需要单独验证。
2026-10-28 21:28:00 +08:00

97 lines
3.7 KiB
PowerShell

# resolve_rva.ps1 - resolve module+RVA to function names using dbghelp + local PDB
# usage: powershell -NoProfile -ExecutionPolicy Bypass -File resolve_rva.ps1 `
# -Module "C:\...\CoreCommand.arx" -Rva 0x58f051,0x7ddcef,0x7e09d0,0x7e1300
param(
[Parameter(Mandatory=$true)][string]$Module,
[Parameter(Mandatory=$true)][string[]]$Rva,
[string]$SymbolPath = ''
)
$ErrorActionPreference = 'Stop'
$mod = (Resolve-Path $Module).Path
$dir = Split-Path $mod -Parent
if (-not $SymbolPath) { $SymbolPath = $dir }
$cs = @'
using System;
using System.Runtime.InteropServices;
public static class Dbg {
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct SYMBOL_INFO {
public uint SizeOfStruct;
public uint TypeIndex;
public ulong Reserved1;
public ulong Reserved2;
public uint Index;
public uint Size;
public ulong ModBase;
public uint Flags;
public ulong Value;
public ulong Address;
public uint Register;
public uint Scope;
public uint Tag;
public uint NameLen;
public uint MaxNameLen;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=1024)]
public byte[] Name;
}
[DllImport("dbghelp.dll", SetLastError=true)]
public static extern bool SymInitialize(IntPtr hProcess, string UserSearchPath, bool fInvadeProcess);
[DllImport("dbghelp.dll", SetLastError=true)]
public static extern ulong SymLoadModuleEx(IntPtr hProcess, IntPtr hFile, string ImageName, string ModuleName,
ulong BaseOfDll, uint DllSize, IntPtr Data, uint Flags);
[DllImport("dbghelp.dll", SetLastError=true)]
public static extern bool SymFromAddr(IntPtr hProcess, ulong Address, out ulong Displacement, ref SYMBOL_INFO Symbol);
[DllImport("dbghelp.dll", SetLastError=true)]
public static extern bool SymCleanup(IntPtr hProcess);
[DllImport("dbghelp.dll")]
public static extern uint SymSetOptions(uint SymOptions);
public const uint SYMOPT_UNDNAME = 0x00000002;
public const uint SYMOPT_LOAD_LINES = 0x00000010;
public const uint SYMOPT_DEBUG = 0x80000000;
}
'@
Add-Type -TypeDefinition $cs -Language CSharp | Out-Null
[Dbg]::SymSetOptions([Dbg]::SYMOPT_UNDNAME) | Out-Null
$proc = [System.Diagnostics.Process]::GetCurrentProcess()
$h = $proc.Handle
if (-not [Dbg]::SymInitialize($h, $SymbolPath, $false)) {
Write-Output ("SymInitialize failed: " + [ComponentModel.Win32Exception]::new([Runtime.InteropServices.Marshal]::GetLastWin32Error()).Message)
exit 1
}
$base = [Dbg]::SymLoadModuleEx($h, [IntPtr]::Zero, $mod, $null, 0, 0, [IntPtr]::Zero, 0)
if ($base -eq 0) {
Write-Output ("SymLoadModuleEx failed: " + [ComponentModel.Win32Exception]::new([Runtime.InteropServices.Marshal]::GetLastWin32Error()).Message)
[Dbg]::SymCleanup($h) | Out-Null
exit 1
}
Write-Output ("module : " + $mod)
Write-Output ("base : 0x{0:x}" -f $base)
Write-Output ("sympath : " + $SymbolPath)
Write-Output ""
foreach ($r in (($Rva -join ',').Split(',') | Where-Object { $_ -ne '' })) {
$off = [Convert]::ToUInt64($r, 16)
$addr = $base + $off
$sym = New-Object Dbg+SYMBOL_INFO
$sym.SizeOfStruct = 88
$sym.MaxNameLen = 1024
$sym.Name = New-Object byte[] 1024
[uint64]$disp = 0
if ([Dbg]::SymFromAddr($h, $addr, [ref]$disp, [ref]$sym)) {
$name = [Text.Encoding]::ASCII.GetString($sym.Name, 0, [int]$sym.NameLen)
Write-Output ("0x{0:x} {1}+0x{2:x} {3}" -f $off, $name, $disp, "")
} else {
Write-Output ("0x{0:x} <no symbol> (err {1})" -f $off, [Runtime.InteropServices.Marshal]::GetLastWin32Error())
}
}
[Dbg]::SymCleanup($h) | Out-Null