Неверный путь к файлу и номер строки в трассировке стека исключений из динамического кода

Мы используем System.Reflection.Emit для генерации кода во время выполнения из исходного кода (да - как в компиляторе). Мы предоставляем правильную информацию о символах в ILGenerator с помощью MarkSequencePoint и т.д. И включаем все флаги отладки на AssemblyBuilder. Сборка хранится в памяти в том же процессе, который скомпилирован и выполняется непосредственно.

При использовании отладчика Visual Studio для перехода по источнику для динамически сгенерированного кода он действительно работает отлично, и Visual Studio, похоже, полностью знает, откуда приходит код с точки зрения файлов и номеров строк.

ОДНАКО - Когда исключения генерируются сгенерированным кодом, объекты System.Exception содержат стеки, которые полностью ошибочны. Они указывают на другие (действительные, но неправильные) файлы и номера строк. Он получает имя класса и метода правильно, но указанный номер файла и строки не имеет никакого отношения к пути кода, из которого действительно произошло исключение.

Файлы, на которые указывает, настолько не связаны друг с другом, кажется, что они не могут быть связаны с встраиванием или оптимизацией. Единственный образец, который я могу заметить, заключается в том, что он, кажется, компенсируется некоторыми файлами (в мнимом отсортированном в алфавитном порядке списке исходных файлов, из которого была создана сборка). Однако эта схема не соответствует 100%, и кажется иррациональным, что это связано с источником проблемы.

Если я создаю объект System.Diagnostics.Debug из Exception, он содержит ту же самую неисправную информацию.

Я предполагаю, что среда выполнения .NET использует те же метаданные для построения трассировок стека Exception, которые использует отладчик для перехода через код, и в этом случае это поведение действительно странно.

Я пытаюсь выяснить, является ли это известной ошибкой в ​​.NET при работе с динамическими сборками в памяти, или если у кого-то были подобные проблемы в других областях.

Ответ 1

Хорошо, я не мог понять, что вызывает проблему, и как заставить .NET вести себя правильно, но по крайней мере мне удалось найти работу, которая также может работать для других, испытывающих ту же проблему.

  • Когда я создаю байт-код CIL, я создаю отдельную базу данных, которая отображает имена методов (полный путь) и IL-смещение обратно к исходным именам файлов и номерам строк.

  • При удалении исключений я проверяю трассировку стека и использую только информацию GetMethod() и GetILOffset() из объектов фрейма стека. Эта информация из CLR оказывается правильной, даже если GetFileName() и GetFileLineNumber() ошибочны.

  • Затем я для каждого фрейма стека использует имя метода и смещение IL, полученное из исключения, для поиска в моей сгенерированной базе данных, чтобы определить фактическое имя файла и номер строки для каждого кадра стека. У меня есть информация о.

  • Кадры, которые я не нахожу в базе данных, обычно представляют собой стековые фреймы в предварительно скомпилированных .NET-модулях, для которых информация, полученная из CLR, действительно правильная. Для этих фреймов я использую GetFileName() и GetFileLineNumber() непосредственно в стеке стека.