Автоматизація розбору дампов падіння додатків

Автоматизація розбору дампов падіння додатків

В даний час, коли компанії звертають велику увагу на якість своїх продуктів, нестабільні програми стають неконкурентоспроможними на сучасному ринку. Багаторазові навантажувальні, регресивні і unit-тестування покращують додатки, проте збої в роботі все ж трапляються. Різні книги пропонують різні розумні підходи до написання захищеного коду, проте ризикну припустити, що додатки падали, падають і будуть падати. Добре, якщо вони падають в тестовій лабораторії, але вони ж можуть падати і у клієнтів. А іноді програми падають з незрозумілих причин через фатального збігу обставин, яке тестер не може і не зможе повторити ... До речі, про полегшення праці тестерів теж варто подумати - вони теж люди, і їм важко підбирати найкоротший шлях до відтворення збою.

Однак відразу обмовлюся - я не можу викласти у відкритий доступ вихідні файли всіх компонентів, що згадуються в статті, так як система, описана нижче, є власністю моєї компанії.

Отже, якщо ви все ще повні ентузіазму - почнемо!

Як все починалося

Деякий час тому ми вирішили використовувати в одному зі своїх продуктів сторонні бібліотеки однієї компанії. Підключили, перевірили - все працювало як годинник. Але в один чорний день почалися поодинокі листи, потім поодинокі дзвінки, а потім почався шквал повідомлень про помилки, про те, що наш додаток нестабільно. Ми почали тестувати це у себе, але у нас нічого не відтворювалося.

Потім почалися поїздки до клієнтів і прохання записати порядок дій, що призводять до збою. Через деякий час винний був знайдений. Так-так, це виявилася саме та бібліотека (але на її місці могла б бути будь-яка інша, в тому числі і наша). Виявилося, що вона частково несумісна з програмними продуктами сторонніх фірм. Три тижні, витрачених на розгляди, ми жили в режимі авралу ...

Це стало для мене уроком. На жаль, та падаюча програма виявилася моєї, через що я тут же зайнявся проблемою створення засобів виявлення помилок. Готових рішень я не знайшов, тому зайнявся розробкою свого.

Термінологія

Дамп падіння (надалі дамп) - спеціальний файл, що збирається за допомогою бібліотеки dbghelp.dll, що містить в собі інформацію про стек додатки в момент падіння. Також містить в собі інформацію про завантажених модулях, хендла (handles), потоках, ділянках пам'яті і т.д. У переважній більшості випадків допомагає розібрати стек падіння додатки.

Release-версія файлу (скорочено release) - бінарний виконуваний файл, що збирається з початкових кодів проекту. Досить сильно відрізняється від налагоджувальної версії (наприклад, наявністю оптимізації і відсутністю ініціалізації даних спеціальними налагоджувальними значеннями). Існує хибна думка, що release-файли налагоджувати не можна. Насправді їх налагоджувати можна, просто за замовчуванням MS Visual Studio не включає підтримку символів в release-версія. У документації Microsoft сказано, що включення підтримки символів незначно збільшує розмір бінарних файлів. Однак, на мою особисту досвіду, розмір файлу збільшується (і значно). В середньому файл збільшується на 100 кілобайт. На великих проектах це не помітно, але маленькі проекти після цього сильно збільшуються в розмірах.

Для включення генерації символів в release-версіях потрібно в настройках компілятора вибрати значення «Generate Program Database» для опції «Debug Information Format» (опція компілятора / Zi). Якщо ви забудете зробити це, файл символів буде побудований не повністю і регламентуватиме по ньому буде неможливо.

PDB-файл (файл символів або просто символи). При компіляції проекту компоновщик будує виконуваний модуль. Фірми-виробники програмного забезпечення вже давно розробили різні методи збереження інформації про рядках вихідних файлів в модулях символів. В даний час найбільш широко (мова йде про Microsoft) використовується формат PDB версії 2 (MS Visual Studio 6.0) і PDB 7.0 (MS Visual Studio 7.0+). Дані формати забезпечують можливість отримання розширеної інформації про виконуваних модулях, в тому числі можливість розбору стека, отримання локальних змінних і т.д.

WinDBG. Один з отладчиков додатків Microsoft. Моя думка полягає в тому, що невеликі системи у себе на комп'ютері дуже зручно налагоджувати в Visual Studio, проте як тільки додаток стає розподіленим і складним, або необхідна повна налагодження в складних умовах, найзручніший засіб - це WinDBG. Повторюся, що це моя особиста думка. Крім того, до складу WinDBG входять різні утиліти для полегшення процесу налагодження.

Загальна структура системи

Для початку потрібно визначитися з функціями системи обробки дампов. Система повинна вміти:

  1. Приймати дампи падінь (надалі просто дампи) від клієнтів і виробляти їх обробку.
  2. Приймати дампи падінь від відділів тестування і контролю якості з можливістю негайної реакції програміста на помилку.
  3. Проводити обробку дампов з метою пошуку програміста, відповідального за компонент, який викликав помилку, і перенаправляти дамп йому.
  4. Заносити записи про помилки в систему контролю помилок (bug tracking system).
  5. Мати можливість систематизувати обробку дампов відділом тестування.

Автоматизація розбору дампов падіння додатків

Таким чином, система повинна складатися з наступних модулів:

  1. Сховище символів. Зберігає в собі як власні символи від програмних компонентів, так і символи зовнішніх бібліотек і програм, в тому числі входять до складу ОС.
  2. Сервер розбору дампов. Використовує в роботі сховище символів. Сервер прослуховує входять мережеві з'єднання, а також періодично перевіряє електронну пошту на наявність нових дампов. Розбір дампов проводиться за допомогою WinDBG і різних його розширень.
  3. Бібліотека збору дампов. Збирає дамп падіння додатки і пересилає його Серверу розбору дампов. У локальному (intranet) режимі пересилає їх безпосередньо на сервер і, в залежності від результатів відповіді сервера, реалізує різні моделі поведінки. У віддаленому (extranet) режимі збирає дамп падіння і пересилає його по електронній пошті.

Розглянемо тепер всі компоненти докладніше.

сховище символів

Тепер у нас є бінарні файли і файли символів. Що з ними робити?

Щоб зрозуміти, що з ними робити, потрібно розглянути типовий сценарій розробки програми:

  1. Програміст створює компонент.
  2. Компонент проходить тестування.
  3. Компонент передається клієнтам.
  4. Програміст продовжує розробку компонента.

Якщо після етапу 4 у клієнта виникають помилки, то існуючий файл символів (побудований після передачі компонента клієнтам) вже нічим не допомагає, так як він вже не відповідає клієнтського компоненту. Тому в момент передачі компонентів клієнтам бінарний файл і файл символів повинні бути збережені. Але де? Можна їх зберігати в окремій папці на диску, але в такому випадку доведеться кожного разу з'ясовувати, що за версія додатка стоїть біля клієнта, після чого копіювати файли в якусь папку на диску, звідки їх і використовувати. Такий підхід зручний, коли файлів мало. Але уявіть, що ви розробляєте кілька компонентів. А тепер уявіть десятки компонентів. А тепер уявіть десятки компонентів за пару місяців роботи. І повідомлення про помилки йдуть не тільки від клієнтів (у яких заздалегідь відомі версії), а ще й від відділу тестування, від технічної підтримки, від відділу контролю якості ... Тому потрібно шукати автоматизоване рішення.

Microsoft пропонує створити спеціальний каталог на диску, який називається «сховищем символів». В даному каталозі створюється дерево папок з назвами, що збігаються з назвами компонентів. У кожній з цих папок знаходяться вкладені папки, що мають спеціальні назви, одержувані методом хеширования бінарних файлів. Це забезпечує швидкий пошук необхідного компонента, по обмеженою інформації про нього (наприклад, з дампа падіння). Для створення такої папки використовується спеціальна утиліта, symstore. Вона сканує папки з компонентами і додає нові компоненти в сховище, звідки їх може вибирати будь-який клієнт. Крім того, є можливість розширення стандартного механізму пошуку файлів шляхом написання своєї реалізації протоколу пошуку.

Приклад, наведений нижче, був отриманий при розборі тестового додатка на чистій машині, де спочатку символів не було. Нижче наведена структура папок, отримана на локальному диску після розбору дампа із закачуванням символів з Інтернету. Як видно з прикладу, WinDBG автоматично завантажив необхідні бібліотеки для розбору (список директорій і їх назви можуть відрізнятися між комп'ютерами в залежності від версій операційних систем).

Програмні продукти Microsoft (Visual Studio 6.0, 7.0+, WinDBG) знають формат такого каталогу і дозволяють зручно з ним працювати. Але виникає питання: ви створили свою сховище символів, поклали туди компоненти, однак падіння відбулося глибоко всередині бібліотек операційної системи, наприклад, в kernel32.dll. У вас немає символів від операційної системи Windows, тому ви не можете розібрати стек падіння (тому що відсутність символів для будь-якої функції, фреймів стека якій присутній в дампі, перешкоджає подальшому розбору списку викликів), тому весь дамп залишиться не розібраним. Однак існує спеціальний сервер в Інтернет, який представляє з себе сховище всіх символів Microsoft (або майже всіх) за останні кілька років. Стандартний протокол пошуку символів працює з цим сервером. Наприклад, зручно налаштувати Visual Studio так, щоб вона шукала символи спочатку у вас на комп'ютері, потім на головному сервері в компанії, потім, якщо символи все ще не знайдені, то закачувала б їх з сервера Microsoft. При цьому система скачування досить інтелектуальна, щоб скопіювати викачані з Інтернету символи і на центральний сервер, і на вашу особисту машину.

У документації написано, що така система коректно працює тільки в режимі одного, але у нас за весь час не було жодної проблеми з розрахованих на багато користувачів режимом.

При великих обсягах сховища символів, пошук по ним істотно сповільнюється, тому фірмою Microsoft була введена нова структура сховища символів, оптимізована під великі обсяги даних. MS Visual Studio 7.0+ і WinDBG здатні працювати з новою структурою сховища, однак MS Visual Studio 6.0 такого формату не знає, тому вам доведеться вирішити, що за формат ви будете використовувати. Якщо ви все ж хочете використовувати MS Visual Studio 6.0, то вам потрібно покласти файл flat.txt в корінь сховища символів, тоді дерево символів буде створюватися в форматі, сумісному з форматом MS Visual Studio 6.0.

Однак, рішення, яке вимагає ручного втручання, значною кількістю помилок. Кожен раз запускати цю утиліту, та ще з купою параметрів командного рядка, та ще простежити за кожним програмістом в окремо - трудомістке завдання. Потрібна автоматизація цього процесу. В Інтернеті існує утиліта «CruiseControl». Дана утиліта призначена для того, щоб сканувати різні джерела даних, в тому числі папки на дисках, каталоги CVS, Subversion і т.д. і в разі змін проводити будь-які дії. Однак вона це робить для інших цілей (автоматизація тестування або «continuos integration» по Фаулеру), але важливо те, що її можна використовувати для власних цілей. А для нас вона може виконувати сканування архіву бінарних компонентів при його зміні.

  • Ми збираємо проект, викладаємо його в CVS (як це зроблено в моїй компанії).
  • Прокидається CruiseControl, виявляє зміна сховища, викликає bat-файл, який запускає symstore, що виконує рекурсивний обхід сховища.

Сервер розбору дампов

Отже, якимось чином отриманий дамп падіння. Виникає питання: «Що тепер з ним робити?».

Спочатку розберемо його руками, щоб зрозуміти, що з нього можна дізнатися. Для цього запустимо WinDBG, де виконаємо наступні кроки:

Я написав маленьке MFC-додаток, що після натискання кнопки викликає функцію CLSIDFromString з невірним покажчиком, що призводить до падіння програми. Код функції наведено нижче: