Errors reading symbol files
While reading a symbol file, GDB occasionally encounters problems,
such as symbol types it does not recognize, or known bugs in compiler
output. By default, GDB does not notify you of such problems, since
they are relatively common and primarily of interest to people
debugging compilers. If you are interested in seeing information
about ill-constructed symbol tables, you can either ask GDB to print
only one message about each such type of problem, no matter how many
times the problem occurs; or you can ask GDB to print more messages,
to see how many times the problems occur, with the command (see section ).
The messages currently printed, and their meanings, include:
-
The symbol information shows where symbol scopes begin and end
(such as at the start of a function or a block of statements). This
error indicates that an inner scope block is not fully contained
in its outer scope blocks.GDB circumvents the problem by treating the inner block as if it had
the same scope as the outer block. In the error message, symbol
may be shown as «» if the outer block is not a
function. -
The symbol information for symbol scope blocks should occur in
order of increasing addresses. This error indicates that it does not
do so.GDB does not circumvent this problem, and has trouble
locating symbols in the source file whose symbols it is reading. (You
can often determine what source file is affected by specifying
. See section .) -
The symbol information for a symbol scope block has a start address
smaller than the address of the preceding source line. This is known
to occur in the SunOS 4.1.1 (and earlier) C compiler.GDB circumvents the problem by treating the symbol scope block as
starting on the previous source line. -
Symbol number n contains a pointer into the string table which is
larger than the size of the string table.GDB circumvents the problem by considering the symbol to have the
name , which may cause other problems if many symbols end up
with this name. -
The symbol information contains new data types that GDB does
not yet know how to read. is the symbol type of the
uncomprehended information, in hexadecimal.GDB circumvents the error by ignoring this symbol information.
This usually allows you to debug your program, though certain symbols
are not accessible. If you encounter such a problem and feel like
debugging it, you can debug with itself, breakpoint
on , then go up to the function
and examine to see the symbol. -
GDB could not find the full definition for a struct or class.
-
The symbol information for a C++ member function is missing some
information that recent versions of the compiler should have output for
it. -
GDB could not parse a type specification output by the compiler.
Go to the first, previous, next, last section, table of contents.
Data inspection
Variables can be inspected in the VARIABLES section of the Run view or by hovering over their source in the editor. Variable values and expression evaluation are relative to the selected stack frame in the CALL STACK section.
Variable values can be modified with the Set Value action from the variable’s context menu. Additionally, you can use the Copy Value action to copy the variable’s value, or Copy as Expression action to copy an expression to access the variable.
Variables and expressions can also be evaluated and watched in the Run view’s WATCH section.
Variable names and values can be filtered by typing while the focus is on the VARIABLES section.
Использование редактора Linux gcc / g ++
2. Как gcc завершает компиляцию
Здесь задействована важная концепция: библиотека функций
Библиотеки функций обычно делятся на статические библиотеки и динамические библиотеки.
- Статическая библиотека относится кСсылка на компиляциюКогда поставить код файла библиотекиДобавить все в исполняемый файлПоэтому сгенерированный файл относительно велик, но файл библиотеки больше не нужен во время выполнения. егоИмя суффикса обычно «.a»
- В отличие от динамической библиотеки, код файла библиотеки не добавляется в исполняемый файл при компиляции и компоновке, а при выполнении программы.Ссылка на библиотеку загрузки файла во время выполнения, Это может снизить накладные расходы системы. Общие динамические библиотекиСуффикс «.so», Как упоминалось ранее, libc.so.6 — это динамическая библиотека. gcc по умолчанию использует динамические библиотеки при компиляции. После установки ссылки gcc может сгенерировать исполняемый файл, как показано ниже. gcchello.o –o привет
- gccБинарная программа, созданная по умолчанию, динамически связана, Это можно проверить с помощью команды file.
- Преимущество динамической компоновки: исполняемая программа имеет небольшой размер. Недостатки: низкая эффективность, сильная зависимость от библиотеки, если библиотека отсутствует, ее невозможно скомпилировать.
- Преимущества статической компоновки: не полагается на библиотеки и имеет хорошую переносимость. Недостатки: исполняемая программа имеет большой размер.
E Активируйте только предварительную обработку, это не создает файл, вам нужно перенаправить его в выходной файл
Debug Console REPL
Expressions can be evaluated with the Debug Console REPL (Read-Eval-Print Loop) feature. To open the Debug Console, use the Debug Console action at the top of the Debug pane or use the View: Debug Console command (⇧⌘Y (Windows, Linux Ctrl+Shift+Y)). Expressions are evaluated after you press Enter and the Debug Console REPL shows suggestions as you type. If you need to enter multiple lines, use Shift+Enter between the lines and then send all lines for evaluation with Enter.
Debug Console input uses the mode of the active editor, which means that the Debug Console input supports syntax coloring, indentation, auto closing of quotes, and other language features.
Note: You must be in a running debug session to use the Debug Console REPL.
Анализируем Hellow, World! с помощью ассемблерного отладчика.
1. Программа начинает выполняться с адреса CS:100. Это заданное нами начальное значение смещения программы типа «*.COM» в памяти — 100h:org 100h.
2. По адресу в памяти CS:100 у нас расположен машинный код (в цифровом шестнадцатеричном виде, как его видит машина — B409). Этот код отладчик преобразует в более понятную для нас ассемблерную форму:mov ah,9
Машинный код B409 преобразуется в mov ah,9 .
3
Жмём F8 (или F7 пока для нас это не важно). Процессор сделал один шаг — и в регистре указателя команд появился адрес следующей команды, которую будет выполнять процессор:IP 0102
Курсор переместился на эту строку:mov dx,0108
Машинный код — BA0801, наш код — mov dx,offset message
Необходимо отметить, что в dx загружается адрес строки байт, определённая в коде:message db «Hello World!»,0Dh,0Ah,’$’ ; строка для вывода.
Мы уже понимаем, что 0108 — это смещение, указывающее на строку символов. Перемещаемся с помощью нажатия клавиши TAB или при помощи курсора мыши в окно данных и клавишей «вниз» клавиатуры или с помощью курсора перемещаемся к смещению 108. По данному адресу находится наша текстовая строка!
Turbo Debugger дизассемблирует данные как код.
4. Директивой .model tiny мы определили модель памяти для нашей программы как СОМ. В ней (в отличие от EXE) сегменты кода, данных и стека объединены.
То есть:CS=DS=SS=ES
Проверяем это. Смотрим на данные сегментных регистров — CS=DS=SS=ES = 4CEA — здорово!
Программа типа «*.com» : CS=DS=SS=ES .
Так как все сегменты владеют одной памятью, то одни и те же её кусочки должны иметь одинаковые значения (CD 20 FF 9F).
Значение по одному и тому же адресу в памяти естественно совпадает.
Посмотрим, что у нас по смещению 100h (начальное значение смещения программы типа «*.COM» в памяти). Везде значение B409 (байты перевернуты младшему байту — младшее смещение, но стеком воспринимается как слово кода, поэтому 09B4).
5. Именованный указатель на нашу строку символов «message»:mov dx,offset message ; адрес строки — в DX…..message db «Hello World!»,0Dh,0Ah,’$’ ; строка для вывода
получил свое естественное цифровое отображение (по смещению 108):CS:0102 BA0801 mov dx,0108…..DS:0108 48 65 6C 6C 6F 20 57 6F Hello WoDS:0110 72 6C 64 21 0D 0A 24 00 rld!
Технические подробности
Функции
GDB предлагает обширные возможности для отслеживания и изменения выполнения компьютерных программ . Пользователь может отслеживать и изменять значения внутренних переменных программы и даже вызывать функции независимо от нормального поведения программы.
Целевые процессоры GDB (по состоянию на 2003 год) включают: Alpha , ARM , AVR , H8 / 300 , Altera Nios / Nios II , System / 370 , System 390 , X86 и его 64-битное расширение X86-64 , IA-64 «Itanium» , Motorola 68000 , MIPS , PA-RISC , PowerPC , SuperH , SPARC и VAX . Менее известные целевые процессоры, поддерживаемые в стандартной версии, включают A29K , ARC , ETRAX CRIS , D10V , D30V , FR-30 , FR-V , Intel i960 , 68HC11 , Motorola 88000 , MCORE , MN10200 , MN10300 , NS32K , Stormy16 и Z8000 . (Новые выпуски, вероятно, не будут поддерживать некоторые из них.) GDB скомпилировал симуляторы даже для менее известных целевых процессоров, таких как M32R или V850 .
GDB все еще активно развивается. Начиная с версии 7.0 новые функции включают поддержку сценариев Python, а с версии 7.8 — также сценариев GNU Guile . Начиная с версии 7.0, доступна поддержка «обратимой отладки», позволяющая откатить сеанс отладки назад, что очень похоже на перемотку сбойной программы, чтобы увидеть, что произошло.
Удаленная отладка
GDB предлагает «удаленный» режим, который часто используется при отладке встроенных систем. Удаленная работа — это когда GDB работает на одной машине, а отлаживаемая программа — на другой. GDB может связываться с удаленной «заглушкой», которая понимает протокол GDB, через последовательное устройство или TCP / IP. Программа-заглушка может быть создана путем связывания с соответствующими файлами-заглушками, поставляемыми с GDB, которые реализуют целевую сторону протокола связи. В качестве альтернативы можно использовать gdbserver для удаленной отладки программы без каких-либо изменений.
Тот же режим также используется KGDB для отладки работающего ядра Linux на уровне исходного кода с помощью gdb. С помощью KGDB разработчики ядра могут отлаживать ядро почти так же, как они отлаживают прикладные программы. Это позволяет размещать точки останова в коде ядра, выполнять пошаговое выполнение кода и наблюдать за переменными. В архитектурах, где доступны регистры аппаратной отладки, можно установить точки наблюдения, которые запускают точки останова при выполнении или доступе к указанным адресам памяти. KGDB требует дополнительной машины, которая подключена к машине для отладки с помощью последовательного кабеля или Ethernet . Во FreeBSD также можно выполнять отладку с использованием прямого доступа к памяти FireWire (DMA).
Графический пользовательский интерфейс
Отладчик не содержит собственного графического пользовательского интерфейса и по умолчанию использует интерфейс командной строки , хотя и содержит текстовый пользовательский интерфейс . Для него было создано несколько интерфейсов, таких как UltraGDB , Xxgdb , Data Display Debugger (DDD), Nemiver , KDbg , отладчик Xcode , GDBtk / Insight и графический интерфейс HP Wildebeest Debugger (WDB GUI). IDE, такие как Codelite , Code :: Blocks , Dev-C ++ , Geany , GNAT Programming Studio (GPS), KDevelop , Qt Creator , Lazarus , MonoDevelop , , NetBeans и Visual Studio, могут взаимодействовать с GDB. В GNU Emacs есть «режим GUD» и существуют инструменты для VIM (например, clewn). Они предлагают возможности, аналогичные отладчикам в IDE.
Некоторые другие инструменты отладки были разработаны для работы с GDB, например, детекторы утечки памяти .
Внутренности
GDB использует системный вызов с именем ptrace (название является сокращением от «трассировки процесса») для наблюдения и управления выполнением другого процесса, а также для проверки и изменения памяти и регистра процесса. Список общих команд gdb и соответствующих вызовов ptrace приведен ниже:
- (gdb) start: PTRACE_TRACEME — делает родителя трассировщиком (вызывается трассировщиком)
- (gdb) attache PID: PTRACE_ATTACH — присоединить к запущенному процессу
- (gdb) stop: kill (child_pid, SIGSTOP) (или PTRACE_INTERRUPT)
- (gdb) продолжить: PTRACE_CONT
- (gdb) регистры информации: PTRACE_GET (FP) REGS (ET) и PTRACE_SET (FP) REGS (ET)
- (gdb) x: PTRACE_PEEKTEXT и PTRACE_POKETEXT
Точка останова реализуется путем замены инструкции по заданному адресу памяти другой специальной инструкцией. Выполнение инструкции точки останова вызывает SIGTRAP.
1.Как можно отлаживать программу
Все обычно начинают писать серьёзную программу с того, что добавляют к ней возможность вести логи её работы. Это очень правильно. Здесь можно только добавить, что неплохо добавить в программу перехват всех сигналов, которые она может получить, и логировать также получение этих сигналов.
Часто бывает так, что одних только логов не хватает. Бывает, что хочется программу отладить по шагам. В Linux для этого есть отладчик GDB. проблема только в том, что раз у нас не x86 платформа, то и отладчик нам нужен для нашей платформы, а не для x86. Как этот отладчик собрать из исходников, будет рассказано дальше.
Бывает, что наша платформа имеет очень мало свободного места в файловой системе, или у неё нет терминального выхода (или он занят) или просто по какой-то причине отлаживаемая программа находится очень далеко, и мы не хотим запускать gdb через терминальную сессию. В этой ситуации можно отладиться с помощью связки gdb-server/gdb. При этом gdb-server должен быть нативным для данной платформы, а gdb — должен быть кросс-отладчиком, т.е. работать на x86, но при этом понимать исполняемый файл целевой платформы.
Бывает также так, что просто по какой-то причине мы вообще не можем использовать никакой из отладчиков (например, между нами и целевой платой нет постоянной устойчивой и достаточно быстрой связи или вообще связи нет), или по какой-то причине под отладчиком программа работает без сбоев, а без отладчика падает. В этой ситуации нам может помочь core-файл (или core-dump). Это посмертный слепок с программы, в момент, когда она приводит к непоправимой ошибке, по нему можно узнать внутри какой функции и в какой строчке произошла ошибка, значения локальных переменных, проследить всю цепочку вызовов.
map-файл — это файл, в котором отображены все видимые линкеру «символы» (т.е. имена функций и переменных), и их адреса, по которым они располагаются. map-файл очень часто бывает полезен, когда вы видите сообщение отладчика, что инструкция вашей программы по адресу 0xXXXXXXXX, обратилась по адресу 0xYYYYYYYY. С помощью map-файла можно выяснить, где в вашей программе какие функции и какие переменные располагаются (есть некоторые тонкости, но всё же map-файл — полезная штуковина).
Точки останова
Информацию о командах этого раздела можно получить, введя
Точки останова — такие, когда GDB приостанавливает выполнение программы. Как уже упоминалось, имеется 3 типа точек останова:
- Breakpoints — точка останова как таковая. Остановка происходит, когда выполнение доходит до определенной строки, адреса или процедуры/функции.
- Watchpoints — точка просмотра. Выполнение программы приостанавливается, если программа обратилась к определенной переменной — либо считала ее значение, либо изменила его.
- Catchpoints — точка отлова. Приостановка происходит при определенном событии (например, получение сигнала). Я не буду касаться точек останова этого типа.
Определение точек останова
Breakpoint
Команда
или, сокращенно
определяет точку останова. В качестве аргумента может выступать
- номер строки. Остановка произойдет при достижении строки программы с этим номером. То, что написано в самой строке, выполняться не будет. Например
(gdb) b 394 Breakpoint 1 at 0x805a650: file maeq.pas, line 394.
- имя процедуры (функции). Отладчик зайдет в эту процедуру и остановит выполнение программы. NB!! Имя процедуры (функции) должно быть указано БОЛЬШИМИ БУКВАМИ. Приведу пример:
(gdb) b CALC Breakpoint 2 at 0x7657c7a: file maeq.pas, line 26.
- если вызвать команду без аргументов, то точка останова поставится на текущей строке.
- также можно явно указывать адрес точки останова (перед адресом надо поставить знак ). Приведу лишь пример для полноты описания:
(gdb) b *0x805a650 Breakpoint 3 at 0x805a650: file maeq.pas, line 394.
Допускается использование нескольких точек останова на одной строке (функции, адресе).
Watchpoint
Существуют различные виды точек просмотра, и задаются они различными командами:
- команда (сокращенно )
(gdb) wa <переменная>
Выполнение программы приостанавливается всякий раз, когда значение указанной переменной изменяется.
NB!! Имя переменной должно быть указано БОЛЬШИМИ БУКВАМИ.
- команда (сокращенно )
(gdb) rw <переменная>
Выполнение приостанавливается всякий раз, когда программа считывает значение указанной переменной.
NB!! Имя переменной должно быть указано БОЛЬШИМИ БУКВАМИ.
- команда (сокращенно )
(gdb) aw <переменная>
Выполнение приостанавливается всякий раз, когда программа обращается к указанной переменной, как для считывания, так и для записи.
NB!! Имя переменной должно быть указано БОЛЬШИМИ БУКВАМИ.
Замечу от себя, что команды и у меня почему-то капризничают — часто не устанавливают точки просмотра на переменную. Зато команда работала всегда.
Управление точками останова
Информацию о всех установленных точках останова можно вывести командой .
Команда имеет много возможностей, но в данном случае воспользуемся лишь следующим ее форматом:
или, кратко
Выводится подробная информация о всех точках останова (как breakpoints, так и watchpoints), включающая — номер — breakpoint или watchpoint — активность — сколько раз программа натыкалась на эту точку — иные характеристики, значение которых мне не совсем понятно
Если какая-то точка останова не нужна, то ее можно сделать неактивной с помощью команды :
(gdb) disable breakpoint <номер этой точки>
Обратно, деактивированная точка останова активируется командой :
(gdb) enable breakpoint <номер этой точки>
Статус точки останова — активна она или нет, легко обозреть той же командой .
Если же точка останова не требуется вообще, то она может быть удалена насовсем.
(gdb) delete breakpoint
а короче
(gdb) d b
Ввод этой команды без аргумента удалит ВСЕ точки останова.
Компиляция и запуск программы в отладчике
Для использование
отладчика программу (каждый исходный файл, если Ваша программа
разделена на несколько файлов) необходимо откомпилировать с
включением отладочной информации. Это делается добавлением ключа компиляции -g, например:
gcc -g file.c
gdb -q имя_выполняемого_файла
run
Внимание! В отладчике запускается исполняемый файл, а не исходный файл программы. Не следует выполнять команду
gdb -q file.c
quit
$ gcc -g first-prog.c $ gdb -q ./a.out Reading symbols from ./a.out...done. (gdb) run Starting program: /home/serg/tmp/gdb/a.out Введите последовательность чисел и нажмите 0 - символ конца последовательности 0 Не удалось прочитать первый элемент (gdb) quit $
Запуск OpenOCD
Запуск OpenOCD осуществляется командой:
openocd -d2 -f interface/olimex-arm-usb-ocd.cfg -f target/lpc2478.cfg
где,
- -d2 уровень вывода отладочных сообщений,
- -f interface/olimex-arm-usb-ocd.cfg указывает на тип отладчика
- -f target/lpc2478.cfg на тип микроконтроллера.
Пример запуска openOCD:
>openocd -d2 -f interface/olimex-arm-usb-ocd.cfg -f target/lpc2478.cfg Open On-Chip Debugger 0.4.0 (2010-02-22-19:05) Licensed under GNU GPL v2 For bug reports, read http://openocd.berlios.de/doc/doxygen/bugs.html debug_level: 2 jtag_nsrst_delay: 100 jtag_ntrst_delay: 100 trst_and_srst srst_pulls_trst srst_gates_jtag trst_push_pull srst_open_drain RCLK - adaptive Info : RCLK (adaptive clock speed) not supported - fallback to 500 kHz Info : JTAG tap: lpc2478.cpu tap/device found: 0x4f1f0f0f (mfg: 0x787, part: 0xf 1f0, ver: 0x4) Info : Embedded ICE version 7 Error: EmbeddedICE v7 handling might be broken Info : lpc2478.cpu: hardware has 2 breakpoint/watchpoint units
Supported Native Debugger Versions
Qt Creator supports native debuggers when working with compiled code. On most supported platforms, the GNU Symbolic Debugger GDB can be used. On Microsoft Windows, when using the Microsoft tool chain, the Microsoft Console Debugger CDB is needed. On macOS and Linux, the LLDB debugger can be used.
The following table summarizes the support for debugging C++ code:
Platform | Compiler | Native Debugger |
---|---|---|
Linux | GCC, ICC | GDB, LLDB |
Unix | GCC, ICC | GDB |
macOS | GCC, Clang | LLDB, FSF GDB (experimental) |
Windows/MinGW | GCC | GDB |
Windows/MSVC | Microsoft Visual C++ Compiler | Debugging Tools for Windows/CDB |
Supported GDB Versions
Starting with version 3.1, Qt Creator requires the Python scripting extension. GDB builds without Python scripting are not supported anymore and will not work. The minimum supported version is GDB 7.5 using Python version 2.7, or 3.3, or newer.
For remote debugging using GDB and GDB server, the minimum supported version of GDB server on the target is 7.0.
Supported LLDB Versions
The LLDB native debugger has similar functionality to the GDB debugger. LLDB is the default debugger in Xcode on macOS for supporting C++ on the desktop. LLDB is typically used with the Clang compiler (even though you can use it with GCC, too).
On macOS you can use the LLDB version delivered with Xcode or build from source. The minimum supported version is LLDB 320.4.
On Linux, the minimum supported version is LLDB 3.8.
Инструмент автоматической сборки проекта Linux-make / Makefile
Зависимость
- Вышеупомянутый файл привет, это зависит от hell.o
- hello.o, это зависит от hello.s
- hello.s, это зависит от hello.i
- hello.i, это зависит от hello.c
принцип
Как работает make? В режиме по умолчанию мы вводим только команду make. Потом:
- make найдет файл с именем «Makefile» или «makefile» в текущем каталоге.
- Если он найден, он найдет первый в файлеЦелевой файл(Target), в приведенном выше примере он найдет файл «hello» и использует этот файл в качестве конечного целевого файла.
- Если файл hello не существует или время модификации файла hello.o, от которого зависит hello, новее, чем файл hello (вы можете использовать прикосновение для проверки), то он выполнит команду, определенную позже, для генерации hello файл.
- Если файл hello.o, от которого зависит hello, не существует, make найдет зависимость файла hello.o в текущем файле и, если найдет ее, сгенерирует файл hello.o в соответствии с этим правилом. (Это немного похоже на процесс укладки)
- Конечно, ваш C-файл и H-файл существуют, поэтому make сгенерирует файл hello.o, а затем использует файл hello.o для объявления конечной задачи make, которая заключается в выполнении файла hello.
- Это зависимость всей программы make. Make будет искать зависимость файлов слой за слоем, пока первый целевой файл не будет окончательно скомпилирован.
- Если в процессе поиска возникает ошибка, например, последний зависимый файл не может быть найден, программа make завершит работу и сообщит об ошибке. Однако в случае ошибки определенной команды или неудачной компиляции make просто проигнорирует ее.
- Make заботится только о зависимостях файлов, то есть, если файл после двоеточия все еще не существует после того, как я найду зависимости, то извините, я не буду работать.
Очистка проекта
- Требуется инженерияЧистый
- Как и в случае с clean, если он прямо или косвенно не связан с первым целевым файлом, то команды, определенные после него, не будут выполняться автоматически, но мы можем показать, что make выполняется. Это команда — «очистить», чтобыОчистите все объектные файлы, чтобы перекомпилировать。
- Но обычно наш чистый целевой файл, мы устанавливаем его как псевдо-цель, используем.PHONY Характеристики модифицированных псевдо-целей:Всегда выполняется。
- Make использует время файла, чтобы определить, был ли файл скомпилирован.
- .PHONY, генерирует псевдо-цель, принцип, по которому ее всегда можно выполнить, заключается в игнорировании времени файла во время выполнения.
2.Логирование
Логирование можно делать по разному: писать в файл, в поток вывода ошибок, или вообще использовать стандартный демон логирования, в любом случае, API подсистемы логирования должен быть удобным
Я под удобством подразумеваю то, что:
1) должна быть возможность выводить форматированные сообщения в стиле printf.
2) должна быть некая иерархическая система важности сообщений, чтоб можно было по желанию включать или выключать сообщения в зависимости от уровня важности
Здесь приведу простейшие функции и макросы для логирования. В реальности надо добавлять разные детали в этот механизм, например, путь к файлу должен задаваться, а не быть жестко вбитым. Возможно, кому-то нужно писать время, когда появилось сообщение, и т.д.
#include <stdarg.h> #include <stdio.h> #include <ctype.h> //isprint #define MESSAGE_SIZE_MAX 300 #define LOG_PATH "/tmp/log.txt" void log(const char *format, ...) { va_list va; char tmp; static FILE *log_file = NULL; if (log_file == NULL) { log_file = fopen(LOG_PATH,"a"); } va_start(va, format); vsnprintf(tmp, MESSAGE_SIZE_MAX, format, va); va_end(va); tmp = 0; tmp = '\n'; fprintf(log_file,"%s\n",tmp); fflush(log_file); } void dump(char *title, void *ptr, int n) { int i = 0; char string = {0}; char buf; int j = 0; int r16 = n % 16; DBG("%s", title); if (NULL != ptr && 0 != n) { for (i = 0; i = ' ') if (isprint(*(((char*)ptr)+i))) { string = *(((char*)ptr)+i); } else { string = '.'; } } if (r16 != 0) { string = '\0'; n = 16 - r16; //padding for (i = 0; i 8) { j += snprintf(buf + j, sizeof(buf) - j, " "); } } j += snprintf(buf + j, sizeof(buf) - j," |%s|", string); DBG("%s", buf); } } #define TRACE log("%s:%s:%d",__FILE__,__FUNCTION__,__LINE__); #define LOG_DBG(...) log(__VA_ARGS__) //#define LOG_DBG(...) #define LOG_ERR(...) log(__VA_ARGS__) //#define LOG_ERR(...) #define LOG_EMER(...) log(__VA_ARGS__) //#define LOG_EMER(...) |
Logpoints
A Logpoint is a variant of a breakpoint that does not «break» into the debugger but instead logs a message to the console. Logpoints are especially useful for injecting logging while debugging production servers that cannot be paused or stopped.
A Logpoint is represented by a «diamond» shaped icon. Log messages are plain text but can include expressions to be evaluated within curly braces (‘{}’).
Just like regular breakpoints, Logpoints can be enabled or disabled and can also be controlled by a condition and/or hit count.
Note: Logpoints are supported by VS Code’s built-in Node.js debugger, but can be implemented by other debug extensions. The Python and Java extensions, for example, support Logpoints.
Next steps
To learn about VS Code’s Node.js debugging support, take a look at:
- Node.js — Describes the Node.js debugger, which is included in VS Code.
- TypeScript — The Node.js debugger also supports TypeScript debugging.
To see tutorials on the basics of Node.js debugging, check out these videos:
- Intro Video — Debugging — Showcases the basics of debugging.
- Getting started with Node.js debugging — Shows how to attach a debugger to a running Node.js process.
To learn about debugging support for other programming languages via VS Code extensions:
- C++
- Python
- Java
To learn about VS Code’s task running support, go to:
Tasks — Describes how to run tasks with Gulp, Grunt, and Jake and how to show errors and warnings.
To write your own debugger extension, visit:
Debugger Extension — Uses a mock sample to illustrate the steps required to create a VS Code debug extension.
Setting up FSF GDB for macOS
To use FSF GDB on macOS, you must sign it and add it to the Qt Creator .
- To create a key for signing FSF GDB, select Keychain Access > Certificate Assistant > Create a Certificate:
- In the Name field, input fsfgdb to replace the existing content.
- In the Certificate Type field, select Code Signing.
- Select the Let me override defaults check box.
- Select Continue, and follow the instructions of the wizard (use the default settings), until the Specify a Location For The Certificate dialog opens.
- In the Keychain field, select System.
- Select Keychain Access > System, and locate the certificate.
- Double click the certificate to view certificate information.
- In the Trust section, select Always Trust in the When using this certificate field, and then close the dialog.
- To sign the binary, enter the following command in the terminal:
codesign -f -s "fsfgdb" $INSTALL_LOCATIONfsfgdb
- In Qt Creator, select Qt Creator > Preferences > Kits > Add to create a kit that uses FSF GDB.
- In the Debugger field, specify the path to FSF GDB (, but with an explicit value for ).
- To use the debugger, add the kit in the Build Settings of the project.
Пример: вывод элементов std::vector
Рассмотрим следующий пример.
#include <iostream> #include <vector> using namespace std; int main() { vector<int> vec; vec.push_back(10); vec.push_back(20); vec.push_back(30); cout << vec.size() << endl; }
Если попытаться просмотреть в GDB содержимое с помощью команды , то получим
(gdb) p vec $1 = {<std::_Vector_base<int, std::allocator<int> >> = { _M_impl = {<std::allocator<int>> = {<__gnu_cxx::new_allocator<int>> = {<No data fields>}, <No data fields>}, _M_start = 0x804c028, _M_finish = 0x804c034, _M_end_of_storage = 0x804c038}}, <No data fields>}
Вряд ли эта информация поможет при отладке. Кое-что, о том как посмотреть содержимое мы уже знаем. Воспользуемся этим, и напишем следующий макрос:
define p_stl_vector set $vec = ($arg0) set $vec_size = $vec._M_impl._M_finish - $vec._M_impl._M_start if ($vec_size != ) set $i = while ($i < $vec_size) printf "Vector Element %d: ", $i p *($vec._M_impl._M_start+$i) set $i++ end end end
Теперь, остановив выполнение в строке 14, получим:
(gdb) p_stl_vector vec Vector Element : $1 = 10 Vector Element 1: $2 = 20 Vector Element 2: $3 = 30
Совсем другое дело!