Что такое трассировка стека и как ее использовать для отладки ошибок приложения?

Убедитесь, что он работает

  1. Убедитесь, что debug — это текущая конфигурация решения.

  2. Если окно Обозреватель решений не отображается, нажмите клавишу CTRL+ALT+L, чтобы отобразить это окно.

  3. Щелкните правой кнопкой мыши conInfo и нажмите кнопку Свойства.

  4. В левой области страницы свойств conInfo в папке Конфигурация убедитесь, что стрелка указывает на отладку.

    Примечание

    В visual C# 2005 и в Visual C# 2005 Express Edition щелкните Debug на странице conInfo.

  5. Над папкой «Конфигурация» в поле список «Конфигурация» щелкните Active (Debug) или Debug, а затем нажмите кнопку ОК. В Visual C# 2005 и в Visual C# 2005 Express Edition щелкните Active (Debug) или Debug в окне Список отламывок конфигурации на странице Отлажка, а затем нажмите кнопку Сохранить в меню Файл.

  6. Нажмите кнопку CTRL+ALT+O, чтобы отобразить окно Вывода.

  7. Нажмите клавишу F5 для запуска кода. Когда появится диалоговое окно с неудачным утверждением, нажмите кнопку Игнорировать.

  8. В окне Консоли нажмите кнопку ENTER. Программа должна завершиться, а в окне Output должен отображаться выход, похожий на следующие:

  9. В окне консоли иOutput.txt должен отображаться следующий вывод:

Примечание

Файл Output.txt расположен в том же каталоге, что и исполняемый conInfo (conInfo.exe). Обычно это папка \bin, в которой хранится источник проекта. По умолчанию это значение равно . В Visual C# 2005 и в Visual C# 2005 Express Edition файлOutput.txtпапке: .

Запрос

Параметры запроса

Параметр Тип Описание Обязательно
applicationId строка Код продукта классического приложения, для которого требуется получить трассировку стека. Чтобы получить идентификатор продукта для классического приложения, откройте любой аналитический отчет для настольного приложения в центре партнеров (например, отчет о работоспособности) и получите идентификатор продукта из URL-адреса. Да
cabIdHash строка Уникальный хэш идентификатора CAB-файла, связанного с ошибкой, для которой требуется получить трассировку стека. Для получения этого значения используйте метод получения подробных сведений об ошибке в классическом приложении, чтобы получить подробные сведения об определенной ошибке в приложении, и значение cabIdHash в тексте ответа этого метода. Да

Пример запроса

В следующем примере показано, как получить трассировку стека с помощью этого метода. Замените параметры applicationId и cabIdHash соответствующими значениями для вашего классического приложения.

Выходные данные трассировки

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

Сведения трассировки всегда записываются как минимум в целевой объект вывода Trace по умолчанию, DefaultTraceListener. Если по каким-то причинам объект DefaultTraceListener был удален, а другие прослушиватели не были добавлены в коллекцию Listeners, сообщения трассировки получены не будут. Дополнительные сведения см. в разделе прослушиватели трассировки.

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

Метод Выходные данные
Указанный текст; если ничего не указано, то стек вызовов. Выходные данные записываются только в том случае, если условие, указанное в качестве аргумента в инструкции, имеет значение false.
Указанный текст; если ничего не указано, то стек вызовов.
Указанный текст.
Указанный текст, если удовлетворено условие, заданное в качестве аргумента в инструкции.
Заданный текст и возврат каретки.
Указанный текст и символ возврата каретки, если удовлетворяется условие, заданное в качестве аргумента в инструкции.

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

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

Методы и всегда записывают указанный текст. , и требуется логический аргумент, который определяет, записывается ли заданный текст в заданный текст; если выражение имеет значение true (для и ), либо значение false (для ). Метод всегда записывает указанный текст. Дополнительные сведения см. в разделе Практическое руководство. Добавление операторов трассировки в код приложения и в справочнике по .NET Framework.

Осмотр

Стек вызовов иногда можно проверить во время работы программы. В зависимости от того, как программа написана и скомпилирована, информация в стеке может использоваться для определения промежуточных значений и трассировки вызовов функций. Это использовалось для генерации детализированных автоматических тестов, а в таких случаях, как Ruby и Smalltalk, для реализации первоклассных продолжений. Например, GNU Debugger (GDB) реализует интерактивную проверку стека вызовов работающей, но приостановленной программы C.

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

Дальнейшее чтение [ править ]

  • Дейкстра, EW (1960). «Рекурсивное программирование». Numerische Mathematik . 2 (1): 312–318. DOI : 10.1007 / BF01386232 .
  • Уилсон, PR; Джонстон, MS; Neely, M .; Болес, Д. (1995). «Динамическое распределение памяти: обзор и критический обзор». Управление памятью . Конспект лекций по информатике. 986 . С. 1–116. CiteSeerX  10.1.1.47.275 . DOI : 10.1007 / 3-540-60368-9_19 . ISBN 978-3-540-60368-9.
  • «2.4. Стек». Руководство по программированию на языке ассемблера MCS-4 — Руководство по программированию микрокомпьютерной системы INTELLEC 4 (предварительная редакция). Санта-Клара, Калифорния, США: Intel Corporation . Декабрь 1973 г. С. 2-7–2-8. MCS-030-1273-1. Архивировано из оригинала 2020-03-01 . Проверено 2 марта 2020 .(Примечание. Intel «S 4-битный процессор 4004 реализует внутренний стек , а не стек в памяти.)

Повышение стабильности и производительности

И последнее, но не менее важное: мы улучшили стабильность и производительность записи работы ЦП

  • Исправили несколько ошибок, которые могут привести к сбоям записи.
  • Построили системную трассировку на основе Perfetto в качестве бэкенда на Android API level 28 и более поздних версиях с использованием новейших инструментов.
  • Оптимизировали код профайлера, чтобы значительно снизить потребление памяти (до 80%) при разборе записанной трассировки, что позволяет открывать и анализировать более длинные записи. Помните, что вы можете увеличить Android Studio при работе с очень длинными трассировками.

Загрузите последнюю версию превью Android Studio 4.1, чтобы попробовать эти функции. Как и всегда, мы ценим ваши отзывы.

  • Новые инструменты Android 11 для обеспечения конфиденциальности и стабильности
  • Как настроить базу данных с Firebase Firestore для Android
  • Корутины Kotlin: как работать асинхронно в Android

Читайте нас в Telegram, VK и

Обработка сигналов и стековые фреймы

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

  • Когда ядро сталкивается с необходимостью уведомления процесса о поступившем сигнале, оно данные в форме структур, присоединяемых к структуре task, содержащей информацию о процессе, после чего устанавливает бит, указывающий на наличие ожидающего обработки сигнала.
  • После этого, когда получающий сигнал процесс планируется к исполнению, его стековый фрейм модифицируется ядром таким образом, чтобы указатель инструкции (EIP) указывал на адрес функции для обработки сигналов. Таким образом, когда процесс выполняется, он ведет себя так, как будто он сам вызвал свою функцию для обработки сигналов перед тем, как его выполнение было приостановлено планировщиком.
  • Начальные шаги по управлению обработкой сигналов производятся в пространстве пользователя внутри библиотеки libc, из которой в конечном счете производится вызов функции реального процесса для обработки сигналов, в которой, в свою очередь, выполняется наша функция обратной трассировки стека.

В результате работы этого механизма двумя первыми элементами с цепочке стековых фреймов во время входа в обработчик сигналов оказываются, соответственно, адрес возврата внутри вашего обработчика сигналов и адрес возврата внутри функции sigaction() из библиотеки libc. Стековый фрейм последней функции, вызываемой до обработки сигнала (которая, в случае сигналов, указывающих на неполадки, также может быть их источником) теряется. Таким образом, если функция B вызвала функцию A, которая в свою очередь привела к ошибке сегментирования и сигналу SIGSEGV, обычная обратная трассировка стека будет включать в себя следующие точки входа:

your_sig_handler()
sigaction() in libc.so
func_B()
main()

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

Часто задаваемые вопросы

Я не хочу применять деобфускацию или добавлять символы в Play Console. Можно ли сделать это в офлайн-режиме?

Для добавления символов в нативных приложениях в Play Console используется ndk-stack, а в Java-приложениях – ReTrace. При желании вы можете скопировать обфусцированные стеки ошибок из Play Console, а затем добавить отладочные символы в подходящем инструменте. Однако эти действия необходимо выполнять вручную для каждого стека ошибок, что замедляет процесс и отнимает много времени. Просто загрузите файлы деобфускации, а остальное Play Console сделает автоматически.

Почему после загрузки файла деобфускации или файла с отладочными символами ошибки ANR и сбои по-прежнему обфусцируются?

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

Почему после загрузки файла деобфускации или файла с отладочными символами ошибки ANR и сбои деобфусцированы только частично?

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

Почему после загрузки файла деобфускации или файла с отладочными символами число ошибок ANR и сбоев уменьшается, но они становятся критичнее?

Без файлов деобфускации одинаковые ошибки ANR или сбои на 32- и 64-разрядных устройствах либо на устройствах ARM и Intel будут показаны отдельно. После загрузки файлов деобфускации мы можем объединить эти сбои в группы, чтобы нагляднее показать наиболее серьезные ошибки ANR и сбои в вашем приложении.

Что, если я забуду загрузить файл?

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

Чтобы не забывать загружать файлы, рекомендуем использовать в процессе сборки наборы App Bundle и плагин Android Gradle 4.1 или более поздней версии. В этом случае вы сможете настроить автоматическое добавление файла отладочных символов в набор App Bundle, как указано на .

Что, если я загружу не тот файл?

Если вы загрузите файл для другой версии приложения, ошибки ANR и сбои будут обфусцироваться. Чтобы исправить это, сделайте следующее:

  1. Откройте Play Console.
  2. Выберите приложение.
  3. В меню слева нажмите Версия > App Bundle Explorer.
  4. В окне выбора в правом верхнем углу экрана укажите нужный объект.
  5. Откройте вкладку Загрузки и прокрутите экран вниз до раздела «Ресурсы».
  6. Нажмите на значок удаления напротив неправильного файла деобфускации или файла отладочных символов.
  7. После того как он будет удален, нажмите на значок загрузки и выберите файл, подходящий для данной версии приложения.

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

Совет. Чтобы избежать ошибок при загрузке файла, рекомендуем использовать в процессе сборки наборы App Bundle и плагин Android Gradle 4.1 или более поздней версии. В этом случае вы сможете настроить автоматическое добавление файла отладочных символов в набор App Bundle, как указано на .

Я использую формат APK. Как перейти к работе с наборами App Bundle?

Информация об этом приводится на .

Мое приложение содержит и нативный, и Java-код. Можно ли одновременно загрузить файл отладочных символов для нативного кода и файл деобфускации для Java?

Да.

Почему в некоторых ошибках ANR не показывается трассировка стека?

Иногда система обнаруживает ошибку ANR, но при этом не получает трассировку стека. В этом случае запись об ошибке ANR сохраняется, чтобы вам было проще выявлять проблемы со стабильностью приложения, а трассировка стека не отображается. Чтобы было удобнее находить и исправлять похожие ошибки ANR без трассировки стека, они объединяются в группы по типу и классу действия.

Стек вызовов

Современные отладчики имеют еще одно информационное окно, которое может быть очень полезным при отладке программ — «Стек вызовов».

Как вы уже знаете, при вызове функции программа оставляет закладку в текущем местоположении, выполняет функцию, а затем возвращается в место закладки. Программа отслеживает все вызовы функций в стеке вызовов.

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

Отобразить окно «Стека вызовов» в Visual Studio можно через :

Примечание: Вы должны находиться в режиме отладки — используйте для этого команду «Шаг с заходом».

Рассмотрим пример:

#include <iostream>

void CallC()
{
std::cout << «C called» << std::endl;
}

void CallB()
{
std::cout << «B called» << std::endl;
CallC();
}

void CallA()
{
CallB();
CallC();
}

int main()
{
CallA();

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

#include <iostream>

voidCallC()

{

std::cout<<«C called»<<std::endl;

}

voidCallB()

{

std::cout<<«B called»<<std::endl;

CallC();

}

voidCallA()

{

CallB();

CallC();

}

intmain()

{

CallA();

return;

}

Укажите точку останова в функции CallC(), а затем запустите отладку. Программа выполнится до точки останова.

Несмотря на то, что вы знаете, что сейчас выполняется CallC(), в программе есть два вызова CallC(): в функции CallB() и в функции CallA(). Какая функция ответственна за вызов CallC() в данный момент? Стек вызовов нам это покажет:

Сначала выполняется main(). Затем main() вызывает CallA(), которая, в свою очередь, вызывает CallB(). Функция CallB() вызывает CallC(). Вы можете щелкнуть дважды по разным строкам в окне «Стек вызовов», чтобы увидеть больше информации о вызываемых функциях. Некоторые IDE переносят курсор непосредственно к вызову указанной функции. Visual Studio переносит курсор к следующей строке, которая находится после вызова функции. Попробуйте! Для того, чтобы возобновить степпинг, щелкните дважды по самой верхней (первой) строке в окне «Стек вызовов» и вы вернетесь к текущей точке выполнения.

Выберите команду «Продолжить». Точка останова должна сработать во второй раз, когда будет повторный вызов функции CallC() (на этот раз из функции CallA()). Всё происходящее вы должны увидеть в окне «Стек вызовов»:

Используйте [ редактировать ]

Обработка звонков на сайт править

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

Обработка записи подпрограммы править

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

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

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

Язык программирования Forth допускает явную намотку стека вызовов (называемого там «стеком возврата»).

Обработка возврата править

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

Раскрутка править

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

В некоторых языках есть другие управляющие структуры, требующие общей раскрутки. Паскаль позволяет глобальному оператору goto передавать управление из вложенной функции в ранее вызванную внешнюю функцию. Эта операция требует, чтобы стек был размотан, удалив столько кадров стека, сколько необходимо для восстановления правильного контекста, чтобы передать управление целевому оператору внутри включающей внешней функции. Аналогично, С имеет setjmpиlongjmp функцию , которые действуют как нелокальный GOTOS. Common Lisp позволяет контролировать то, что происходит при разворачивании стека, с помощью специального оператора.

При применении продолжения стек (логически) разматывается, а затем перематывается вместе со стеком продолжения. Это не единственный способ реализовать продолжения; например, используя несколько явных стеков, приложение продолжения может просто активировать свой стек и намотать значение, которое нужно передать. Язык программирования Scheme позволяет выполнять произвольные переходы в определенных точках при «раскручивании» или «перемотке» стека управления при вызове продолжения.

Панель анализа

Говоря об анализе, мы хотим выделить новую панель анализа (Analysis Panel), представленную в Android Studio 4.0, в правой колонке окна Profiler.

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

Чтобы сделать эту панель анализа полезной, мы изучали способы получения полезных аналитических данных. В дополнение к , и , уже присутствующим в профайлере центрального процессора, мы добавили вкладку со сводкой (Summary) в Android Studio 4.1 Canary 10 для распределения состояния потока, статистики событий трассировки и т.д. Например, довольно часто нам нужно узнать больше о повторяющемся событии трассировки. На вкладке со сводкой отображаются основные статистические данные (количество, минимум, максимум и т. д.), а также наиболее продолжительные события выбранного события трассировки. Вы даже можете перейти к другому событию, выбрав строку таблицы.

Статистика и наиболее продолжительные события трассировки

Безопасность [ править ]

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

Одна из таких атак включает заполнение одного буфера произвольным исполняемым кодом, а затем переполнение того же или другого буфера для перезаписи некоторого адреса возврата значением, которое указывает непосредственно на исполняемый код. В результате, когда функция возвращается, компьютер выполняет этот код. Этот вид атаки может быть легко блокирован W ^ X . [ необходима цитата ] Подобные атаки могут быть успешными даже при включенной защите W ^ X, включая атаку возврата к libc или атаки, исходящие от программирования, ориентированного на возврат . Были предложены различные меры по снижению рисков, такие как хранение массивов в полностью отдельном месте от стека возврата, как в случае с языком программирования Forth.

Отслеживание переменных

Отслеживание переменных — это процесс проверки значений переменных во время отладки. Например:

#include <iostream>

int main()
{
int x = 1;
std::cout << x << » «;

x = x + 1;
std::cout << x << » «;

x = x + 2;
std::cout << x << » «;

x = x + 4;
std::cout << x << » «;

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

#include <iostream>

intmain()

{

intx=1;

std::cout<<x<<» «;

x=x+1;

std::cout<<x<<» «;

x=x+2;

std::cout<<x<<» «;

x=x+4;

std::cout<<x<<» «;

return;

}

Результат выполнения программы:

Используя команду «Выполнить до текущей позиции» переместитесь к строке :

К этому моменту переменная уже создана и инициализирована, поэтому, при проверке этой переменной, вы должны увидеть число .

Самый простой способ отслеживания простых переменных (как ) — это наведение курсора мыши на элемент. Большинство современных отладчиков поддерживают эту возможность:

Обратите внимание, вы можете навести курсор мыши на любую другую переменную (и на любой строке):

В Visual Studio есть еще одна возможность — «Быстрая проверка». Выделите переменную с помощью мыши :

Появится специальное окно с текущим значением переменной:

Хорошо, теперь закройте это окно.

Значения переменных можно отслеживать и во время выполнения отладки. Переместитесь с помощью  к строке :

Значение переменной должно поменяться на . Проверьте!

Внутренняя реализация

В случае, если у вас возникнет вопрос о том, как осуществить доступ к информации о состоянии стека в программе на языке C, ответ будет очень простым: вы не сможете получить доступа к этой информации. На самом деле управление стеком в значительной мере зависит от платформы, на которой выполняется приложение и язык C не предоставляет никаких возможностей для воздействия на этот процесс стандартным образом. Реализация функции backtrace() в библиотеке glibc содержит различные участки кода для разных платформ, использующие либо внутренние переменные GCC (__builtin_frame_address и __builtin_return_address), либо ассемблерный код.

В случае использования платформы i386 (реализация находится в файле glibc-x.x.x/sysdeps/i386/backtrace.c) несколько строк ассемблерного кода используются для доступа к содержимому регистров ebp и esp центрального процессора, которые содержат адрес текущего стекового фрейма и указателя стека для каждой выполняющейся функции:

register void *ebp __asm__ ("ebp");
register void *esp __asm__ ("esp");

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

На этом этапе вам все еще требуется преобразовать адреса возврата в имена функций, а эта операция зависит от формата исполняемых файлов, который вы используете. В случае использования формата ELF эта операция осуществляется при помои внутренней функции для динамического связывания (_dl_addr(), смотрите файл glibc-x.x.x/sysdeps/generic/elf/backtracesyms.c).

Описание [ править ]

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

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

Поскольку существует только один в этом важном контексте, он может быть передан как в стеке (неявно, «задачи»); однако, в языке программирования Forth стек данных или параметры стека доступна более явно , чем в стеке вызовов и обычно упоминается как в стеке (см ниже)

В языках программирования высокого уровня особенности стека вызовов обычно скрыты от программиста. Им предоставляется доступ только к набору функций, а не к памяти самого стека. Это пример абстракции . С другой стороны, для большинства языков ассемблера требуется участие программистов в управлении стеком. Фактические детали стека на языке программирования зависят от компилятора , операционной системы и доступного набора инструкций .

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: