Add UI to manage the list of ignored PDBs for callstacks. Closes #3329

This commit is contained in:
baldurk
2024-06-27 13:46:47 +01:00
parent 6990a6b046
commit 41adeb65b1
10 changed files with 228 additions and 93 deletions
+1 -1
View File
@@ -46,6 +46,6 @@ By default a symbol server will be used, as well as a few default locations such
PDB locate prompt: Prompt to locate a PDB that cannot be found.
If a PDB cannot be located then you have the option of permanently ignoring that PDB. This can be useful for third party libraries for which no PDB will ever be available. If you don't ignore the PDB you will be prompted to locate it the next time you open a capture that references it.
If a PDB cannot be located then you have the option of permanently ignoring that PDB. This can be useful for third party libraries for which no PDB will ever be available. If you don't ignore the PDB you will be prompted to locate it the next time you open a capture that references it. The list of ignored PDBs is given in the settings window in the UI, where you can remove a PDB from it.
Once the symbols have been successfully resolved the callstack section of the API inspector will contain any callstack that was collected for the given action or API call. You can select and copy any levels and paste them elsewhere if you wish.
+6
View File
@@ -175,6 +175,12 @@ The complete details of the analytics can be found in the page about :doc:`../be
Core options
------------
| :guilabel:`Ignored DLLs for callstack symbol resolution` Default: ``Empty``
Here you can see a list of DLLs (on windows only) which have been permanently ignored for callstack symbol resolution. You can remove any or all of the items on the list and you will be prompted to locate them again the next time symbols are resolved which needs them.
For more information you can consult :doc:`../how/how_capture_callstack`.
| :guilabel:`Shader debug search paths` Default: ``Empty``
Here you can choose which locations to search in, and in which order, when looking up a relative path for unstripped debug info.
+39 -17
View File
@@ -29,12 +29,12 @@
#include "Code/QRDUtils.h"
#include "Code/Resources.h"
OrderedListEditor::OrderedListEditor(const QString &itemName, BrowseMode browse, QWidget *parent)
OrderedListEditor::OrderedListEditor(const QString &itemName, ItemButton mode, QWidget *parent)
: RDTableWidget(parent)
{
setFont(Formatter::PreferredFont());
m_BrowseMode = browse;
m_ButtonMode = mode;
setDragEnabled(true);
setDragDropOverwriteMode(false);
@@ -49,7 +49,7 @@ OrderedListEditor::OrderedListEditor(const QString &itemName, BrowseMode browse,
horizontalHeader()->setMinimumSectionSize(50);
verticalHeader()->setHighlightSections(false);
if(m_BrowseMode == BrowseMode::None)
if(m_ButtonMode == ItemButton::None)
{
setColumnCount(1);
setHorizontalHeaderLabels({itemName});
@@ -58,7 +58,14 @@ OrderedListEditor::OrderedListEditor(const QString &itemName, BrowseMode browse,
else
{
QStringList labels;
labels << itemName << tr("Browse");
labels << itemName;
switch(m_ButtonMode)
{
case ItemButton::None: labels << lit("????"); break;
case ItemButton::BrowseFile:
case ItemButton::BrowseFolder: labels << tr("Browse"); break;
case ItemButton::Delete: labels << tr("Delete"); break;
}
setColumnCount(2);
setHorizontalHeaderLabels(labels);
@@ -73,14 +80,17 @@ OrderedListEditor::~OrderedListEditor()
{
}
QToolButton *OrderedListEditor::makeBrowseButton()
QToolButton *OrderedListEditor::makeButton()
{
QToolButton *ret = new QToolButton(this);
ret->setIcon(Icons::folder_page_white());
if(m_ButtonMode == ItemButton::Delete)
ret->setIcon(Icons::del());
else
ret->setIcon(Icons::folder_page_white());
ret->setAutoRaise(true);
QObject::connect(ret, &QToolButton::clicked, this, &OrderedListEditor::browse);
QObject::connect(ret, &QToolButton::clicked, this, &OrderedListEditor::buttonActivate);
return ret;
}
@@ -96,8 +106,8 @@ void OrderedListEditor::setItems(const QStringList &strings)
{
setItem(i, 0, new QTableWidgetItem(strings[i]));
if(m_BrowseMode != BrowseMode::None)
setCellWidget(i, 1, makeBrowseButton());
if(m_ButtonMode != ItemButton::None)
setCellWidget(i, 1, makeButton());
}
// if we added any strings above the new item row was automatically
@@ -106,7 +116,7 @@ void OrderedListEditor::setItems(const QStringList &strings)
addNewItemRow();
resizeColumnToContents(0);
if(m_BrowseMode != BrowseMode::None)
if(m_ButtonMode != ItemButton::None)
resizeColumnToContents(1);
setUpdatesEnabled(true);
@@ -114,19 +124,22 @@ void OrderedListEditor::setItems(const QStringList &strings)
void OrderedListEditor::addNewItemRow()
{
if(!allowAddition())
return;
insertRow(rowCount());
QTableWidgetItem *item = new QTableWidgetItem(QString());
item->setFlags(item->flags() & ~(Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled));
setItem(rowCount() - 1, 0, item);
if(m_BrowseMode != BrowseMode::None)
if(m_ButtonMode != ItemButton::None)
{
item = new QTableWidgetItem(QString());
item->setFlags(item->flags() & ~(Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled));
setItem(rowCount() - 1, 1, item);
setCellWidget(rowCount() - 1, 1, makeBrowseButton());
setCellWidget(rowCount() - 1, 1, makeButton());
}
}
@@ -134,8 +147,11 @@ QStringList OrderedListEditor::getItems()
{
QStringList ret;
int count = rowCount();
// don't include the last 'new item' entry
for(int i = 0; i < rowCount() - 1; i++)
if(allowAddition())
count--;
for(int i = 0; i < count; i++)
ret << item(i, 0)->text();
return ret;
@@ -158,7 +174,7 @@ void OrderedListEditor::cellChanged(int row, int column)
{
// enable dragging
item(row, 0)->setFlags(item(row, 0)->flags() | (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled));
if(m_BrowseMode != BrowseMode::None)
if(m_ButtonMode != ItemButton::None)
delete takeItem(row, 1);
addNewItemRow();
@@ -173,7 +189,7 @@ void OrderedListEditor::cellChanged(int row, int column)
recurse = false;
}
void OrderedListEditor::browse()
void OrderedListEditor::buttonActivate()
{
QWidget *tool = qobject_cast<QWidget *>(QObject::sender());
@@ -184,10 +200,16 @@ void OrderedListEditor::browse()
QWidget *rowButton = cellWidget(i, 1);
if(rowButton == tool)
{
if(m_ButtonMode == ItemButton::Delete)
{
this->removeRow(i);
return;
}
QString sel;
if(m_BrowseMode == BrowseMode::Folder)
if(m_ButtonMode == ItemButton::BrowseFolder)
sel = RDDialog::getExistingDirectory(this, tr("Browse for a folder"));
else
else if(m_ButtonMode == ItemButton::BrowseFile)
sel = RDDialog::getOpenFileName(this, tr("Browse for a file"));
if(!sel.isEmpty())
+13 -7
View File
@@ -28,11 +28,12 @@
class QToolButton;
enum class BrowseMode
enum class ItemButton
{
None,
Folder,
File,
BrowseFolder,
BrowseFile,
Delete,
};
class OrderedListEditor : public RDTableWidget
@@ -40,22 +41,27 @@ class OrderedListEditor : public RDTableWidget
Q_OBJECT
public:
explicit OrderedListEditor(const QString &itemName, BrowseMode browse, QWidget *parent = 0);
explicit OrderedListEditor(const QString &itemName, ItemButton button, QWidget *parent = 0);
~OrderedListEditor();
void setItems(const QStringList &strings);
QStringList getItems();
bool allowAddition() { return m_allowAddition; }
void setAllowAddition(bool allow) { m_allowAddition = allow; }
private slots:
// manual slots
void cellChanged(int row, int column);
void browse();
void buttonActivate();
private:
void keyPressEvent(QKeyEvent *e) override;
BrowseMode m_BrowseMode;
ItemButton m_ButtonMode;
bool m_allowAddition = true;
void addNewItemRow();
QToolButton *makeBrowseButton();
QToolButton *makeButton();
};
+1 -1
View File
@@ -66,7 +66,7 @@
<item>
<widget class="QLabel" name="pipeLabel">
<property name="text">
<string></string>
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+3 -3
View File
@@ -565,12 +565,12 @@ QWidget *SettingDelegate::createEditor(QWidget *parent, const QStyleOptionViewIt
listEditor.setWindowTitle(tr("Edit values of %1").arg(QString(settingName)));
listEditor.setWindowFlags(listEditor.windowFlags() & ~Qt::WindowContextHelpButtonHint);
BrowseMode mode = BrowseMode::None;
ItemButton mode = ItemButton::None;
if(QString(o->name).contains(lit("DirPath"), Qt::CaseSensitive))
mode = BrowseMode::Folder;
mode = ItemButton::BrowseFolder;
else if(QString(o->name).contains(lit("Path"), Qt::CaseSensitive))
mode = BrowseMode::File;
mode = ItemButton::BrowseFile;
OrderedListEditor list(tr("Entry"), mode);
+64 -2
View File
@@ -207,6 +207,19 @@ SettingsDialog::SettingsDialog(ICaptureContext &ctx, QWidget *parent)
}
}
#if !defined(Q_OS_WIN32)
ui->chooseIgnoresLabel->hide();
ui->chooseIgnores->hide();
#endif
{
const SDObject *getPaths = RENDERDOC_GetConfigSetting("Win32.Callstacks.IgnoreList");
if(!getPaths)
{
ui->chooseIgnores->setEnabled(false);
}
}
if(const SDObject *setting = RENDERDOC_GetConfigSetting("DXBC.Disassembly.FriendlyNaming"))
{
ui->ShaderViewer_FriendlyNaming->setChecked(setting->AsBool());
@@ -605,7 +618,7 @@ void SettingsDialog::on_chooseSearchPaths_clicked()
listEditor.setWindowTitle(tr("Shader debug info search paths"));
listEditor.setWindowFlags(listEditor.windowFlags() & ~Qt::WindowContextHelpButtonHint);
OrderedListEditor list(tr("Search Path"), BrowseMode::Folder);
OrderedListEditor list(tr("Search Path"), ItemButton::BrowseFolder);
QVBoxLayout layout;
QDialogButtonBox okCancel;
@@ -645,6 +658,55 @@ void SettingsDialog::on_chooseSearchPaths_clicked()
}
}
void SettingsDialog::on_chooseIgnores_clicked()
{
QDialog listEditor;
listEditor.setWindowTitle(tr("Ignored DLLs for callstack symbol resolution"));
listEditor.setWindowFlags(listEditor.windowFlags() & ~Qt::WindowContextHelpButtonHint);
OrderedListEditor list(tr("Ignored DLL"), ItemButton::Delete);
list.setAllowAddition(false);
QVBoxLayout layout;
QDialogButtonBox okCancel;
okCancel.setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
layout.addWidget(&list);
layout.addWidget(&okCancel);
QObject::connect(&okCancel, &QDialogButtonBox::accepted, &listEditor, &QDialog::accept);
QObject::connect(&okCancel, &QDialogButtonBox::rejected, &listEditor, &QDialog::reject);
listEditor.setLayout(&layout);
const SDObject *getPaths = RENDERDOC_GetConfigSetting("Win32.Callstacks.IgnoreList");
QStringList items;
for(const SDObject *c : *getPaths)
items << c->data.str;
list.setItems(items);
int res = RDDialog::show(&listEditor);
if(res)
{
items = list.getItems();
SDObject *setPaths = RENDERDOC_SetConfigSetting("Win32.Callstacks.IgnoreList");
setPaths->DeleteChildren();
setPaths->ReserveChildren(items.size());
for(int i = 0; i < items.size(); i++)
setPaths->AddAndOwnChild(makeSDString("$el"_lit, items[i]));
RENDERDOC_SaveConfigSettings();
}
}
void SettingsDialog::on_ExternalTool_RGPIntegration_toggled(bool checked)
{
RENDERDOC_SetConfigSetting("AMD.RGP.Enable")->data.basic.b = checked;
@@ -699,7 +761,7 @@ void SettingsDialog::on_TextureViewer_ChooseShaderDirectories_clicked()
listEditor.setWindowTitle(tr("Custom shaders search directories"));
listEditor.setWindowFlags(listEditor.windowFlags() & ~Qt::WindowContextHelpButtonHint);
OrderedListEditor list(tr("Shaders Directory"), BrowseMode::Folder);
OrderedListEditor list(tr("Shaders Directory"), ItemButton::BrowseFolder);
QVBoxLayout layout;
QDialogButtonBox okCancel;
@@ -76,6 +76,7 @@ private slots:
// core
void on_configEditor_clicked();
void on_chooseSearchPaths_clicked();
void on_chooseIgnores_clicked();
void on_ExternalTool_RGPIntegration_toggled(bool checked);
void on_ExternalTool_RadeonGPUProfiler_textEdited(const QString &rgp);
void on_browseRGPPath_clicked();
+33 -13
View File
@@ -297,11 +297,11 @@ e.g. 1000 * 10 = 1e4</string>
</widget>
</item>
<item row="10" column="1">
<widget class="QComboBox" name="Formatter_OffsetSizeDisplayMode">
<property name="toolTip">
<string>Auto: decimal by default and hexadecimal if above a certain threshold, Decimal: always use decimal, Hexadecimal: always use hexadecimal.</string>
</property>
</widget>
<widget class="QComboBox" name="Formatter_OffsetSizeDisplayMode">
<property name="toolTip">
<string>Auto: decimal by default and hexadecimal if above a certain threshold, Decimal: always use decimal, Hexadecimal: always use hexadecimal.</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_5">
@@ -569,7 +569,27 @@ This option overrides that and will always replay locally if the local context i
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_11">
<widget class="QLabel" name="chooseIgnoresLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Ignored DLLs for callstack symbol resolution</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="chooseIgnores">
<property name="text">
<string>Ignored DLLs list</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_31">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
@@ -581,14 +601,14 @@ This option overrides that and will always replay locally if the local context i
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QPushButton" name="chooseSearchPaths">
<property name="text">
<string>Choose paths</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_18">
<property name="toolTip">
<string>RenderDoc can optionally have integration with AMD's Radeon GPU Profiler, to allow capturing RGP from RenderDoc and allowing interop between the two.
@@ -600,7 +620,7 @@ After interop is enabled you will need to reload any capture.</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QCheckBox" name="ExternalTool_RGPIntegration">
<property name="toolTip">
<string>RenderDoc can optionally have integration with AMD's Radeon GPU Profiler, to allow capturing RGP from RenderDoc and allowing interop between the two.
@@ -612,7 +632,7 @@ After interop is enabled you will need to reload any capture.</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="label_17">
<property name="toolTip">
<string>Locates the RadeonGPUProfiler.exe which will be used to interop with when generating and opening RGP profiles.</string>
@@ -622,14 +642,14 @@ After interop is enabled you will need to reload any capture.</string>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLineEdit" name="ExternalTool_RadeonGPUProfiler">
<property name="toolTip">
<string>Locates the RadeonGPUProfiler.exe which will be used to interop with when generating and opening RGP profiles.</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QPushButton" name="browseRGPPath">
<property name="toolTip">
<string>Locates the RadeonGPUProfiler.exe which will be used to interop with when generating and opening RGP profiles.</string>
@@ -639,7 +659,7 @@ After interop is enabled you will need to reload any capture.</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<item row="6" column="0" colspan="2">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
+67 -49
View File
@@ -35,6 +35,7 @@
#include <algorithm>
#include "common/formatting.h"
#include "core/core.h"
#include "core/settings.h"
#include "dbghelp/dbghelp.h"
#include "os/os_specific.h"
#include "strings/string_utils.h"
@@ -43,6 +44,13 @@
#include <string>
// magic value that the config vars default to. If we see this, we'll upgrade the old .ini
#define UNINITIALISED_VAR ":uninit:var:"
RDOC_CONFIG(rdcarray<rdcstr>, Win32_Callstacks_IgnoreList, {},
"Modules which are ignored when resolving callstacks on Windows.");
RDOC_CONFIG(rdcstr, Win32_Callstacks_MSDIAPath, UNINITIALISED_VAR, "The path to the msdia dll.");
struct AddrInfo
{
rdcstr funcName;
@@ -89,8 +97,8 @@ rdcwstr GetSymSearchPath()
if(len == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
{
// set up a default sympath to look up MS's symbol servers and cache them locally in RenderDoc's
// appdata folder.
// set up a default sympath to look up MS's symbol servers and cache them locally in
// RenderDoc's appdata folder.
PWSTR appDataPath;
SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_SIMPLE_IDLIST | KF_FLAG_DONT_UNEXPAND,
NULL, &appDataPath);
@@ -166,8 +174,8 @@ HRESULT MakeDiaDataSource(IDiaDataSource **source)
// if it loaded, we should be able to manually load up DIA
// thanks to https://stackoverflow.com/a/2466264/4070143 for details of how to 'manually' create a
// COM object from msdia
// thanks to https://stackoverflow.com/a/2466264/4070143 for details of how to 'manually' create
// a COM object from msdia
typedef decltype(&DllGetClassObject) PFN_DllGetClassObject;
@@ -503,7 +511,6 @@ static bool InitDbgHelp()
*slash = 0;
}
#if ENABLED(RDOC_X64)
wcscat_s(path, L"/dbghelp.dll");
#else
@@ -735,45 +742,57 @@ rdcstr Win32CallstackResolver::pdbBrowse(rdcstr startingPoint)
Win32CallstackResolver::Win32CallstackResolver(bool interactive, byte *moduleDB, size_t DBSize,
RENDERDOC_ProgressCallback progress)
{
rdcwstr configPath = StringFormat::UTF82Wide(FileIO::GetAppFolderFilename("config.ini"));
if(Win32_Callstacks_MSDIAPath() == UNINITIALISED_VAR)
{
FILE *f = NULL;
_wfopen_s(&f, configPath.c_str(), L"a");
if(f)
fclose(f);
}
RDCLOG("Updating callstack resolve config from ini");
DWORD sz = 2048;
wchar_t *inputBuf = new wchar_t[sz];
for(;;)
{
DWORD read =
GetPrivateProfileStringW(L"renderdoc", L"ignores", NULL, inputBuf, sz, configPath.c_str());
if(read == sz - 1)
rdcwstr configPath = StringFormat::UTF82Wide(FileIO::GetAppFolderFilename("config.ini"));
{
sz *= 2;
delete[] inputBuf;
inputBuf = new wchar_t[sz];
continue;
FILE *f = NULL;
_wfopen_s(&f, configPath.c_str(), L"a");
if(f)
fclose(f);
}
break;
DWORD sz = 2048;
wchar_t *inputBuf = new wchar_t[sz];
for(;;)
{
DWORD read =
GetPrivateProfileStringW(L"renderdoc", L"ignores", NULL, inputBuf, sz, configPath.c_str());
if(read == sz - 1)
{
sz *= 2;
delete[] inputBuf;
inputBuf = new wchar_t[sz];
continue;
}
break;
}
rdcstr ignores = StringFormat::Wide2UTF8(inputBuf);
{
DWORD read = GetPrivateProfileStringW(L"renderdoc", L"msdiapath", NULL, inputBuf, sz,
configPath.c_str());
if(read > 0)
DIA2::msdiapath = inputBuf;
}
delete[] inputBuf;
split(ignores, pdbIgnores, ';');
}
rdcstr ignores = StringFormat::Wide2UTF8(inputBuf);
else
{
DWORD read =
GetPrivateProfileStringW(L"renderdoc", L"msdiapath", NULL, inputBuf, sz, configPath.c_str());
if(read > 0)
DIA2::msdiapath = inputBuf;
pdbIgnores = Win32_Callstacks_IgnoreList();
DIA2::msdiapath = StringFormat::UTF82Wide(Win32_Callstacks_MSDIAPath());
}
delete[] inputBuf;
// check we can create an IDiaDataSource
{
IDiaDataSource *source = NULL;
@@ -791,7 +810,6 @@ Win32CallstackResolver::Win32CallstackResolver(bool interactive, byte *moduleDB,
#else
#define DIA140 L"bin\\msdia140.dll"
#endif
const wchar_t *DIApaths[] = {
// try to see if it's just in the PATH somewhere
L"msdia140.dll",
@@ -801,10 +819,12 @@ Win32CallstackResolver::Win32CallstackResolver(bool interactive, byte *moduleDB,
L"C:\\Program Files\\Microsoft Visual Studio\\2022\\Professional\\DIA SDK\\" DIA140,
L"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\DIA SDK\\" DIA140,
L"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\DIA SDK\\" DIA140,
L"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\DIA SDK\\" DIA140,
L"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\DIA "
L"SDK\\" DIA140,
L"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\DIA SDK\\" DIA140,
L"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\DIA SDK\\" DIA140,
L"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Professional\\DIA SDK\\" DIA140,
L"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Professional\\DIA "
L"SDK\\" DIA140,
};
for(size_t i = 0; i < ARRAY_COUNT(DIApaths); i++)
@@ -858,17 +878,11 @@ Win32CallstackResolver::Win32CallstackResolver(bool interactive, byte *moduleDB,
hr = DIA2::MakeDiaDataSource(&source);
}
// save whatever msdia path we found
WritePrivateProfileStringW(L"renderdoc", L"msdiapath", DIA2::msdiapath.c_str(),
configPath.c_str());
}
SAFE_RELEASE(source);
}
split(ignores, pdbIgnores, ';');
byte *chunks = moduleDB + 8;
byte *end = chunks + DBSize - 8;
@@ -1020,11 +1034,15 @@ Win32CallstackResolver::Win32CallstackResolver(bool interactive, byte *moduleDB,
modules.push_back(m);
}
std::sort(pdbIgnores.begin(), pdbIgnores.end());
pdbIgnores.erase(std::unique(pdbIgnores.begin(), pdbIgnores.end()) - pdbIgnores.begin(), ~0U);
merge(pdbIgnores, ignores, ';');
WritePrivateProfileStringW(L"renderdoc", L"ignores", StringFormat::UTF82Wide(ignores).c_str(),
configPath.c_str());
SDObject *ignoreList = RenderDoc::Inst().SetConfigSetting("Win32.Callstacks.IgnoreList");
ignoreList->DeleteChildren();
ignoreList->ReserveChildren(pdbIgnores.size());
for(rdcstr &i : pdbIgnores)
ignoreList->AddAndOwnChild(makeSDString("$el"_lit, i));
RenderDoc::Inst().SetConfigSetting("Win32.Callstacks.MSDIAPath")->data.str =
StringFormat::Wide2UTF8(DIA2::msdiapath);
RENDERDOC_SaveConfigSettings();
}
Win32CallstackResolver::~Win32CallstackResolver()