Как отлаживать программу без отладчика?

Интервью вопрос -

Часто довольно легко отлаживать программу, когда у вас возникли проблемы с вашим кодом. Вы можете поместить часы, точки останова и т.д. Ждать намного проще из-за отладчика.

Но как отлаживать программу без отладчика?

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

Есть ли другие подходы, кроме этого?

Как общий вопрос, он не ограничивается каким-либо конкретным языком. Поэтому, пожалуйста, поделитесь своими мыслями о том, как бы вы это сделали?

EDIT. При отправке ответа укажите полезный ресурс (если есть) о какой-либо концепции. например Вход
Это будет полезно для тех, кто вообще не знает об этом (это включает меня, в некоторых случаях:)

ОБНОВЛЕНИЕ: Michal Sznajderhas поставил настоящий "лучший" ответ, а также сделал его сообществом wiki.Really заслуживает много голосов.

Ответ 1

На самом деле у вас есть много возможностей. Либо с перекомпиляцией исходного кода, либо без него.

С перекомпиляцией.

  • Дополнительно logging. Либо в журналы программы, либо используя системный журнал (например, OutputDebugString или Журнал событий в Windows). Также используйте следующие шаги:
    • Всегда включать отметку времени по крайней мере до нескольких секунд.
    • Рассмотрим добавление идентификатора потока в случае многопоточных приложений.
    • Добавьте хороший вывод ваших структур.
    • Не печатайте перечисления только с% d. Используйте несколько ToString() или создайте функцию EnumToString() (что подходит для вашего языка)
    • ... и будьте осторожны: протоколирование изменений, поэтому в случае многопоточной обработки проблемы могут исчезнуть.
    • Подробнее об этом здесь.
  • Ввести больше утверждений
  • Модульные тесты
  • "Аудиовизуальный" мониторинг: если что-то происходит,
    • использовать звуковой сигнал
    • воспроизведение системного звука
    • запустите некоторые светодиоды, включив аппаратную линию GPIO (только во встроенных сценариях).

Без перекомпиляции

  • Если ваше приложение использует сеть любого типа: Packet Sniffer или я просто выберу для вас: Wireshark
  • Если вы используете базу данных: запросы монитора отправляются в базу данных и базу данных.
  • Используйте виртуальные машины для тестирования точно такой же настройки операционной системы и оборудования, что и ваша система.
  • Используйте какой-то монитор системных вызовов. Это включает
    • В поле Unix strace или dtrace
    • В инструментах Windows из прежних Sysinternals таких инструментов, как http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx, ProcessExplorer и аналогично
    • В случае Windows GUI: посмотрите Spy ++ или для WPF Snoop (хотя второй я не использовал)
    • Рассмотрите возможность использования некоторых инструментов профилирования для вашей платформы. Это даст вам обзор того, что происходит в вашем приложении.
  • [Настоящий хардкор] Мониторинг оборудования: используйте осциллограф (он же O-Scope) для контроля сигналов на аппаратных линиях
  • Отладка исходного кода: вы садитесь с исходным кодом и просто притворяетесь листом бумаги и карандашом, что вы компьютер. Его так называемый анализ кода или отладка "on-my-eyes"
  • Отладка контроля источника. Сравните diffs вашего кода со временем, когда "it" работает и сейчас. Ошибка может быть где-то там.

И некоторые общие советы в конце:

  • Не забывайте о тексте в столбцы и сводную таблицу в Excel. Вместе с некоторыми текстовыми инструментами (awk, grep или perl) вы получите невероятный пакет анализа. Если у вас более 32 тыс. Записей, следует использовать Access как источник данных.
  • Основы Data Warehousing могут помочь. С помощью простого куба вы можете анализировать тонны временных данных за несколько минут.
  • Сбрасывать ваше приложение стоит упомянуть. Либо в результате сбоя, либо просто на регулярной основе.
  • Всегда генерирует отладочные символы (даже для релизов сборки).
  • Почти последнее, но не менее важное: на большинстве платформ мэров есть встроенный отладчик командной строки (даже Windows!). С некоторыми трюками, такими как условная отладка и break-print-continue, вы можете получить довольно хороший результат с неясными ошибками.
  • И действительно последнее, но не менее важное: используйте свой мозг и вопрос все.

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

Ответ 2

Прежде всего, что делает отладка на самом деле? Расширенные отладчики дают вам машинные перехваты, чтобы приостановить выполнение, изучить переменные и потенциально изменить состояние запущенной программы. Большинству программ не нужно все это для их отладки. Существует много подходов:

  • Трассировка: реализовать какой-то механизм ведения журнала или использовать существующую, такую ​​как dtrace(). Обычно стоит реализовать какую-то функцию, подобную printf, которая может выводить обычно отформатированный вывод в системный журнал. Затем просто введите состояние из ключевых точек в вашей программе в этот журнал. Верьте или нет, в сложных программах это может быть более полезно, чем сырая отладка с помощью реального отладчика. Журналы помогают вам узнать, как вы попали в неприятности, в то время как отладчик, который ловушки при сбое, предполагает, что вы можете перепроектировать, как вы его получили, из любого состояния, в котором вы уже находитесь. Для приложений, в которых вы используете другие сложные библиотеки, которые у вас нет, авария в середине их, журналы часто намного полезнее. Но для записи ваших сообщений в журнале требуется определенная дисциплина.

  • Самосознание программы/библиотеки: для решения очень специфических событий сбоя я часто реализовывал обертки в системных библиотеках, таких как malloc/free/realloc, которые расширения, которые могут делать такие вещи, как прогулочная память, обнаружение двойных освобождений, попытки освобождать ненужные указатели, проверять очевидные переполнения буфера и т.д. Часто вы можете делать такие вещи для своих важных внутренних типов данных - как правило, вы можете выполнять проверки целостности для таких вещей, как связанные списки (они могут 't loop, и они не могут указывать на la-la land.) Даже для таких вещей, как объекты синхронизации ОС, часто вам нужно только знать, какой поток, или какой номер файла и строки (захвачен __FILE__, __LINE__), последний пользователь синхронизирующего объекта должен был помочь вам разобраться в состоянии гонки.

  • Если вы сумасшедшие, как я, вы могли бы фактически реализовать свой собственный мини-отладчик внутри своей собственной программы. Это действительно единственный вариант в самоотражающем языке программирования или в языках, подобных C, с некоторыми OS-перехватами. При компиляции C/С++ в Windows/DOS вы можете реализовать обратный вызов "сбой", который запускается при срабатывании любой ошибки программы. Когда вы компилируете свою программу, вы можете создать файл .map, чтобы выяснить, что относительные адреса всех ваших публичных функций (чтобы вы могли выработать начальное смещение загрузчика, вычитая адрес main() из адреса, указанного в вашем .map файл). Поэтому, когда происходит сбой (даже нажав ^ C во время прогона, например, вы можете найти свои бесконечные циклы), вы можете взять указатель стека и отсканировать его для смещений в обратных адресах. Обычно вы можете просматривать свои регистры и реализовывать простую консоль, чтобы вы могли изучить все это. И вуаля, у вас есть половина реального отладчика. Продолжайте это, и вы можете воспроизвести механизм отладки консоли VxWorks.

  • Другой подход - это логический вывод. Это связано с №1. В принципе любое аварийное или аномальное поведение в программе происходит, когда она перестает вести себя, как ожидалось. Вам нужно иметь некоторый метод обратной связи, зная, когда программа ведет себя нормально, а затем ненормально. Ваша цель состоит в том, чтобы найти точные условия, по которым ваша программа правильно ведет себя неправильно. С printf()/журналами или другой обратной связью (например, включение устройства во встроенную систему - на ПК имеется динамик, но на некоторых материнских платах также есть цифровой дисплей для отчетов по этапам BIOS; встраиваемые системы часто имеют COM-порт, который вы можете использовать) вы можете вывести по крайней мере двоичные состояния хорошего и плохого поведения в отношении состояния запуска вашей программы с помощью инструментария вашей программы.

  • Связанный метод является логическим выводом относительно версий кода. Часто программа работала отлично в одном состоянии, но некоторая более поздняя версия больше не работает. Если вы используете хороший источник управления, и вы применяете философию "вершина дерева всегда должна работать" среди вашей команды разработчиков, вы можете использовать бинарный поиск, чтобы найти точную версию кода, в котором произошел сбой. Вы можете использовать diffs, чтобы вывести, какое изменение кода выдает ошибку. Если diff слишком велик, тогда у вас есть задача попытаться изменить этот код на более мелкие шаги, где вы сможете более эффективно применять бинарный поиск.

Ответ 3

Несколько предложений:

1) Утверждает. Это должно помочь вам выработать общие ожидания в разных состояниях программы. Также ознакомьтесь с кодом

2) Единичные тесты. Я использовал их порой, чтобы вникать в новый код и тестировать API-интерфейсы

Ответ 4

Одно слово: журнал.

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

Java: log4j

.Net: NLog или log4net

Python: Запись в Python

PHP: Pear Logging Framework

Ruby: Ruby Logger

C: log4c

Ответ 5

Думаю, вам просто нужно написать тесты на тонкую зернистость.

Мне также нравится писать симпатичный принтер для моих структур данных.

Ответ 6

Я думаю, что остальная часть интервью может пойти примерно так...

Кандидат: Итак, вы не покупаете отладчики для своих разработчиков?
Интервьюер: Нет, у них есть отладчики.

Кандидат. Итак, вы ищете программистов, которые из мазохизма или сундука hamartia усложняют себе жизнь, даже если они будут менее продуктивными?
Интервьюер: Нет, я просто пытаюсь понять, знаете ли вы, что бы вы сделали в ситуации, которая никогда не произойдет.

Кандидат: Я полагаю, что добавил бы записи или заявления на печать. Могу ли я задать вам аналогичный вопрос?
Интервьюер: Конечно.

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

Ответ 7

В системах * nix strace и/или dtrace может рассказать вам очень многое о выполнении вашей программы и библиотек, которые она использует.

Ответ 8

Экспертная оценка. Вы просматриваете код в течение 8 часов, и ваш мозг просто показывает вам, что вы хотите видеть в коде. Свежая пара глаз может иметь значение.

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

Ответ 9

Двоичный поиск во времени также является методом: если у вас есть исходный код, хранящийся в репозитории управления версиями, и вы знаете, что версия 100 работает, но версия 200 не работает, попробуйте проверить, работает ли версия 150. Если это так, ошибка должна быть между версиями 150 и 200, поэтому найдите версию 175 и посмотрите, работает ли она... и т.д.

Ответ 10

  • использовать println/log in
  • используйте DB explorer для просмотра данных в DB/файлах
  • писать тесты и ставить утверждения в подозрительные места

Ответ 11

В более общем плане вы можете отслеживать побочные эффекты и выходные данные программы и запускать определенные события в программе извне.

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

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

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

Ответ 12

как все сказали:

  • Вход
  • Утверждает
  • Дополнительный вывод

&

ваш любимый менеджер задач или процесс Исследователь

ссылки здесь и здесь

Ответ 13

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

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

Вы можете получить реальную фантазию и даже настроить поток, который прослушивает последовательный терминал и отвечает на команды. Я также сделал это и выполнил простые команды, чтобы сбрасывать список, видеть внутренние переменные и т.д. Из простого последовательного порта RS-232 9600 бод!

Ответ 14

Spy ++ (и совсем недавно Snoop для WPF) являются огромными для получения информации об ошибках Windows UI.

Ответ 15

Хорошим чтением будет Delta Debugging от Андреаса Целлера. Это похоже на двоичный поиск для отладки