Интерпретировать символ COMDAT файла COFF как удобочитаемую сигнатуру функции

Я хочу интерпретировать символ COMDAT файла COFF
Символ COMDAT

?make@DNameStatusNode@@SAPAV1@W4DNameStatus@@@Z

Как я могу интерпретировать это как

(public: static class DNameStatusNode * __cdecl DNameStatusNode::make(enum DNameStatus))

Благодарю.

2

Решение

Это будет «украшенное» (искаженное) имя функции C ++, сгенерированное Visual Studio (и VS-совместимыми компиляторами Windows), а не символ COMDAT.

Самый простой способ — провести символ через UNDNAME.EXEутилита, которая поставляется с Visual Studio. За исключением этого, вы можете использовать UnDecorateSymbolName() функция в библиотеке Dbghelp.dllили недокументированная внутренняя функция __unDName() (что, насколько мне известно, это то, что UNDNAME использует); Я предполагаю, что вы хотя бы немного знакомы с этой функцией, учитывая, что DName является одним из его вспомогательных классов. [Обратите внимание, что хотя эти инструменты в основном точны, в некоторых случаях они дают сбой (например, указатель const-ness, определенные символы C ++ / CLI или функционально-локальные классы, объявленные в extern "C" функции (в том числе main()).]

Если ничего не помогает, вы также можете попытаться раскрутить имя вручную, что потребует знакомства с самой схемой искажения; если вы не знакомы с внутренней информацией MS, это может потребовать значительных экспериментов и / или исследований, но это наиболее точный способ. Есть несколько простых рекомендаций, которые могут помочь с этим:

  • Имена почти всегда начинаются с ведущих ?, Если нет, то ? будут предшествовать специальные модификаторы (такие как __imp_ за __declspec(dllimport) или же ?@ для CodeView), с правильным именем, начинающимся с ?,
  • После ведущих ?, сегмент до @@ является квалифицированным именем объекта, разбитым на отдельные имена компонентов (сначала имя символа, затем каждое, содержащее имя области действия; область действия пространства имен и класса обрабатываются одинаково для этого этапа процесса искажения); за каждым из имен компонентов, составляющих квалифицированное имя, сразу же следует один @, который действует как терминатор для этого имени, а полное имя завершается автономным @ (обычно создает двойной @@). Прочитайте это справа налево, заменяя любой @ с оператором области :: и останавливаясь на втором @ в двойном @@, [Обратите внимание, что есть также случаи, когда это правило не соблюдается, и что шаблоны имен объектов действительно странно. Также обратите внимание, что когда пользовательский тип (enum, class, struct, union) встречается во время информации о типе, его квалифицированное имя будет использоваться в соответствии с обычными правилами квалифицированного именования, за исключением того, что 1) ему будет предшествовать идентификатор вместо знака вопроса1, и 2) имя будет сокращено, если это возможно2.]
    • Некоторые специальные объекты (такие как операторы, внутренние вспомогательные функции и внутренние вспомогательные объекты) будут иметь специальные имена, которые принимают форму ?x, где x является цифрой или заглавной буквой, которой предшествуют 0-2 подчеркивания; обратите внимание, что эти имена действуют как специальные сокращения2, и, как таковые, являются не заканчивается одним @, В связи с этим, специальные субъекты-члены будут иметь имя, подобное ??_FCLS@@QAEXXZ (закрытие конструктора по умолчанию для class ::CLS), и специальные объекты, не являющиеся членами, будут иметь имена, оканчивающиеся одним @ вместо двойного @@ (такие как ??_H@YGXPAXIHP6EPAX0@Z@Zитератор векторного конструктора; Обратите внимание, что ??_H@ это его полное имя, и все, что после этого является информацией о типе).
  • Сегмент после @@ содержит всю соответствующую информацию о типе, и очень трудно объяснить, не вдаваясь в много подробно. Я бы предложил использовать в качестве справочного материала такой ресурс, как «Соглашения о вызовах для различных компиляторов и операционных систем C ++» Агнера Фога, и / или страницу Викиверситета «Искаженное имя в Visual C ++»; хотя их информация не на 100% точна, она достаточно точна, чтобы прочитать большинство искаженных имен, с которыми вы столкнетесь.

Надеюсь это поможет.


1: Одно из следующего будет использоваться для указания типа UDT:

  • Enum: W4 [Обратите внимание, что это технически представляет enum : int, но по какой-то причине компилятор искажает все типы перечислений как W4 и хранит информацию о базовом типе в другом месте.]
  • Учебный класс: V
  • Struct: U
  • Союз: T

За ним последует квалифицированное имя UDT, которое заканчивается @@ по-прежнему.

class  CL; // Is: VCL@@
struct ST; // Is: UST@@
enum   EN; // Is: W4EN@@
union  UN; // Is: TUN@@

namespace X { class CL; } // Is: VCL@X@@

2: Если какое-либо из имен компонентов в квалифицированном имени UDT уже встречалось при перетаскивании символа (либо как часть квалифицированного имени символа, либо как часть квалифицированного имени параметра (чтение параметров слева направо)), и оно был одним из первых 10 встреченных имен, как имя, так и его окончание @ будет сокращено до цифры, представляющей это ранее использованное имя. Сокращения индексируются нулями, а фактическое имя символа считается именем 0,

namespace Y {
void func(X::CL param);
// Is: ?func@Y@@YAXVCL@X@@@Z
}

namespace X {
void func(CL param);
// Is: ?func@Y@@YAXVCL@1@@Z
// "X@" is replaced with "1".
}

Как уже упоминалось, некоторые специальные объекты (операторы, определенные внутренние вспомогательные функции и определенные внутренние вспомогательные объекты) также используют правила сокращений имен, используя специальные сокращения, жестко запрограммированные в компиляторе; интересно, что большинствоoperator сущности имеют внутренние имена, которые отличаются от сокращений. Как и в случае обычных сокращений, эти специальные сокращения расширяются до имени и его окончания @; из-за этого за специальной аббревиатурой сразу же будет следовать либо завершение квалифицированного имени, либо @или любыми содержащимися областями.

// Containing scopes example, with 'scalar deleting destructor':
class CL {
public:
~CL();
};
CL::~CL() {} // Non-trivial destructor.

// If an instance of the above class is deleted with "delete", the compiler will create
// hidden member functions 'scalar deleting destructor' and 'vector deleting destructor'.
// The former will have this mangled symbol:
// ??_GCL@@QAEPAXI@Z
// Note that there's no '@' between '?_G' (function name) & 'CL@' (containing scope name).// Global example, with 'vector constructor iterator':
class CL {
public:
CL();
};
CL::CL() {} // Non-trivial constructor.

CL cls[3]; // Create an array of class with non-trivial ctor.
// The compiler uses the 'vector constructor iterator' to create the array and initialise
// each instance.
// It has the mangled symbol:
// ??_H@YGXPAXIHP6EPAX0@Z@Z
// Note that there's no '@' between '?_H' (function name) & '@' (qualified name terminator).
1

Другие решения