Как мне вставить исходный код в pdb и использовать его в отладчике?

ПРИМЕЧАНИЕ: моя цель - C# нацеливание на CLR с обычным MSIL на случай, если что-то будет работать, но не в более общем случае.

Некоторые существующие примеры поддержки отладки исходного кода

Недавно был выпущен проект Sourcepack, который позволяет пользователю переписать исходные пути в файле pdb, чтобы они указывали на разные места. Это очень полезно, когда у вас есть источник для сборки, но вы не хотите пытаться поместить его в то же расположение файловой системы, что и при сборке.

http://lowleveldesign.wordpress.com/2011/08/26/sourcepack-released/

Для проектов с открытым исходным кодом отличной идеей является использование http://www.symbolsource.org/ для упрощения получения символов и исходного текста для пользователей вашего проекта.

проблема

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

По умолчанию pdb для проекта включают в себя указатели на файлы на диске (IIRC), а затем индексация источника может добавить возможность встраивать указатели в исходные местоположения (например, в систему управления версиями), при этом исходный сервер затем использует указатели, чтобы на самом деле получить источник.

Цель

Кажется, что может быть проще (для определенных сборок, таких как отладка и / или только для внутреннего использования) просто поместить фактический источник в pdb (фактически просто разыменовать указатель, записанный в данный момент в PDB). Кажется, что тогда вы можете пропустить всю часть исходного сервера (по крайней мере, теоретически) и устранить несколько зависимостей от истории времени отладки. Хранить исходный код как сжатый или нет в значительной степени ортогонально, но первый проход, вероятно, не сделает этого, чтобы упростить его реализацию для существующих отладчиков.

Поскольку бинарная история сопоставления PDB уже очень хороша, размещение источника в PDB будет даже лучше, чем указатель на сервер источника, поскольку указатель может со временем сломаться (система управления исходным кодом перемещается или изменяется на другую систему, или что угодно), но фактический источник, сидящий в PDB, хорош "навсегда".

Чем это отличается от поддержки "исходного сервера"?

(это было добавлено путем редактирования после комментария Тиграна, спрашивающего, какие выгоды будут)

"Базовый" сценарий, с которым это следует сравнить, - это сценарий "нормальной" отладки с использованием "нормального" экземпляра исходного сервера сегодня. В этом сценарии (AFAIK) механизм отладки получает указатель от PDB (через альтернативный поток), а затем использует зарегистрированные серверы источника, чтобы попытаться получить источник через этот указатель. Поскольку данная сборка, как правило, будет включать в себя несколько исходных файлов, существует либо один указатель, который включает базовое местоположение, либо есть несколько указателей в PDB (или что-то еще), но это должно быть ортогонально этому обсуждению.

Для проекта, в котором желательно сохранить источник скрытым / недоступным (например, большинство продуктов Microsoft, включая Windows, Office, Visual Studio и т. Д.), Наличие в PDB указателей намного лучше, чем фактический источник (даже если бы он был зашифрованы). Такие указатели не имеют смысла без необходимого доступа к сети и разрешений, поэтому такой подход означает, что вы можете доставить PDB любому человеку на планете, не беспокоясь о том, что он сможет получить доступ к вашему источнику (в худшем случае они увидят, как ваш источник Дерево устроено, я бы подумал).

Тем не менее, существует 2 больших набора проектов (и в частности, сборок), в которых не существует преимущества "скрыть источник".

Первая - это сборки, которые используются только людьми, которые все равно имеют доступ к источнику. Сборки, выполненные на вашей собственной машине, которые никогда не покинут эту машину, являются отличным примером, так как злоумышленнику в любом случае потребуется прочитать файлы из вашей файловой системы, чтобы получить исходный код, поэтому чтение из одного файла (.cs) против другого (.pdb) - относительно небольшая разница с точки зрения сложности атаки / вектора. Аналогично, сборки, которые выполняются и передаются в тестовую / промежуточную среду, где люди, имеющие доступ к pdb на машине, равны или являются подмножеством людей, которые могут получить доступ к источнику "нормально".

Вторые - это (несколько очевидно) проекты с открытым исходным кодом, где источник проекта в любом случае уже открыт для всех, поэтому скрывать источник от кого-либо бесполезно.

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

Выгоды?

Принимая во внимание вышеприведенные описания, список потенциальных преимуществ, которые могут позволить это, включает (но не ограничивается:) те, которые появляются в моей голове на данный момент:

  • Не нужно заниматься настройкой поддержки исходного сервера. Это просто работает (IJW), по крайней мере, когда / если отладчики знали, что искать в pdb.
    • В то же время, вы все еще можете сделать "фиксированный" исходный сервер, который был просто фиктивным, который извлекал источник и возвращал его вызывающей стороне. Такая конфигурация может быть одинаковой для всех (например, с использованием localhost), тем не менее, устраняя текущую необходимость фактической настройки исходного сервера.
  • Нет необходимости в сборке для включения "индексации источника"
    • Поскольку сборка в любом случае считывает исходные файлы и записывает файлы pdb, мы просто модифицируем то, что написано в pdb, и не принимаем никаких перфолдов во время сборки для выполнения сетевых вызовов или чтения данных, которых у нас еще нет в памяти.
    • До "встроенной" поддержки сборки для вставки исходного кода это мог быть простой шаг после сборки, который, вероятно, был реализован сначала с помощью небольшого форка проекта Sourcepack, поскольку он уже выполняет работу по чтению / изменению файлов PDB:)
  • Нет зависимости от команды / проекта, имеющего систему контроля версий
  • Отсутствие зависимости от конкретной версии каждого файла, входящей в систему контроля версий (большинство людей не регистрируются для каждой сборки, которую они делают в своей IDE)
  • Нет необходимости иметь доступ к конкретной системе контроля версий, которая имеет файл
    • в случае DVCS, например, указатель PDB может относиться к некоторому "случайному" экземпляру git или mercurial или какому-либо другому, не обязательно тому, к которому у вас есть доступ
    • инструментальные средства исходного сервера для отслеживания этой версии обратно на экземпляры сервера исходного контроля, к которым у вас есть доступ (если он даже существует), еще не существует AFAIK)
  • Нет проблем, если проект умирает (удаляется) или перемещается
    • например, если проект перемещается от одного к другому: самодостаточно, sourceforge, github, bitbucket, codeplex, code.google.com и т. д.
  • Нет проблем, если машина, на которой вы отлаживаете, не имеет (или недостаточно) доступа к сети
    • Например, если вы выполняете "сетевой KVM" в поле для отладки проблемы, но у него либо нет сети, либо он может общаться только с отключенными сетями, так что он не может получить доступ к вашему серверу управления источниками).
  • в крайнем случае, возможность восстановить часть исходного кода проекта из сборки.;)

ПРИМЕЧАНИЕ: другой подход будет включать в себя источник в фактической сборке (например, в качестве ресурса), но лучшим выбором будет pdb (легко доставить сборку без pdb, нет нормального перфорационного удара исполнения, если источник находится в pdb так как сборка того же кода и того же размера и т. д.)

Как реализовать?

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

Я думаю, что-то вроде:

  1. Добавьте шаг после сборки, который будет делать что-то похожее на Sourcepack, но вместо изменения указателя он заменит его фактическим источником.
    • В зависимости от того, что нужно сделать исходному серверу, ему может понадобиться префикс, или фактический источник будет находиться в другом альтернативном потоке данных, а "указатель" будет обновлен до чего-то "source-in-pdb: ads-foo.cs". или что угодно. префикс или указатель может также включать способ хранения исходного файла (несжатый, gzip, bzip2 и т. д. вместе с кодировкой файла)
  2. Реализуйте "исходный сервер", который фактически извлекает исходный код из рассматриваемой pdb и возвращает его обратно.
    • Не знаю, достаточно ли информации у API исходного сервера для определения местоположения PDB, не говоря уже о том, будет ли у него разрешение на фактическое чтение содержимого.

Санитарная проверка?

С болтовней выше в стороне, вопросы действительно:

  • Такая вещь уже существует? (и если да, пожалуйста, укажите указатели!)
  • Предполагая, что он еще не существует, имеет ли вышесказанное смысл в качестве реализации первого прохода? Есть ли подводные камни или сложности, о которых говорилось выше?
  • Предполагая "нет" и "да" для вышеизложенного, существует ли существующий проект, который имеет смысл с точки зрения принятия этого (он близок или находится в их существующей области)?

1 ответ

Решение

Я прочитал об этом и хотел бы обобщить мое понимание для ясности

Сегодня отладчик использует PDB для получения пути к файлу на диске и контрольной суммы, которая была скомпилирована для создания заданного раздела исполняемого файла. Затем отладчик пытается загрузить файл, используя как локальный диск, так и доступный сервер символов. По этому предложению мы бы пропустили посредника, просто внедрив сам файл в PDB. Эврика, больше не нужно искать источник!

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

Первый - это фактическое встраивание исходного кода в PDB. Это очень выполнимо. PDB - это, по сути, облегченная файловая база данных. Существует структура того, что он кодирует, но AFAIK вы можете поместить все, что хотите, в определенные слоты (например, значения / типы локальных переменных). Для некоторых слотов могут быть ограничения по размеру, но я уверен, что вы могли бы изобрести схему кодирования, чтобы разбить большие файлы на куски.

Второй аспект заключается в том, что отладчик фактически загружает файл из PDB, а не ищет его на диске. Я не настолько знаком с этой частью отладчика, но насколько я понимаю, он использует только 2 фрагмента информации, чтобы найти файл

  1. Путь к файлу на диске
  2. Контрольная сумма указанного файла (используется для устранения неоднозначности файлов с одинаковым именем)

Я почти уверен, что это единственная информация, которую он передает на сервер символов. Это делает невозможным внедрение сервера символов, потому что у него не будет доступа к PDB (если, конечно, я прав).

Я копался в надежде, что есть VS COM-компонент, который вы можете переопределить, что позволит вам перехватить загрузку файла для заданного пути, но я не смог его найти.

Один подход, я думаю, был бы осуществим, хотя был бы

  1. Вставить источник в PDB
  2. Имейте инструмент, который может и извлечь источник в известное местоположение и переписать PDB, чтобы указать на это место.

Это не совсем то, что вы хотите.

Другие вопросы по тегам