cpp
examples
examples.cpp⚙️cpp
/**
* GDB Debugging Examples
* Compile with: g++ -g -O0 examples.cpp -o examples
* Run with: gdb ./examples
*/
#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <thread>
#include <mutex>
using std::cout;
using std::endl;
// ============================================================================
// EXAMPLE 1: Basic Debugging - Variables and Stepping
// ============================================================================
void calculateSum() {
int a = 10;
int b = 20;
int sum = a + b;
cout << "Sum: " << sum << endl;
// GDB Session:
// (gdb) break calculateSum
// (gdb) run
// (gdb) next
// (gdb) print a
// $1 = 10
// (gdb) print b
// $2 = 20
// (gdb) next
// (gdb) print sum
// $3 = 30
}
// ============================================================================
// EXAMPLE 2: Array/Vector Inspection
// ============================================================================
void inspectContainers() {
int arr[5] = {10, 20, 30, 40, 50};
std::vector<int> vec = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; ++i) {
arr[i] *= 2;
}
for (auto& v : vec) {
v *= 3;
}
// GDB Session:
// (gdb) break inspectContainers
// (gdb) run
// (gdb) next (until after the loops)
//
// Print array:
// (gdb) print arr
// $1 = {20, 40, 60, 80, 100}
// (gdb) print arr[0]@5
// $2 = {20, 40, 60, 80, 100}
//
// Print vector:
// (gdb) print vec
// (gdb) print vec._M_impl._M_start[0]@5
// Or with pretty printing:
// (gdb) set print pretty on
// (gdb) print vec
}
// ============================================================================
// EXAMPLE 3: Pointer Debugging
// ============================================================================
struct Node {
int data;
Node* next;
Node(int d) : data(d), next(nullptr) {}
};
void debugPointers() {
Node* head = new Node(1);
head->next = new Node(2);
head->next->next = new Node(3);
// Traverse
Node* current = head;
while (current) {
cout << current->data << " ";
current = current->next;
}
cout << endl;
// Cleanup
while (head) {
Node* temp = head;
head = head->next;
delete temp;
}
// GDB Session:
// (gdb) break debugPointers
// (gdb) run
// (gdb) next (until after building list)
//
// Examine linked list:
// (gdb) print *head
// $1 = {data = 1, next = 0x...}
// (gdb) print *head->next
// $2 = {data = 2, next = 0x...}
// (gdb) print head->next->next->data
// $3 = 3
}
// ============================================================================
// EXAMPLE 4: Stack Trace Analysis
// ============================================================================
void level3(int x) {
int result = x * 2;
cout << "Level 3: result = " << result << endl;
// Set breakpoint here to see call stack
}
void level2(int x) {
int processed = x + 10;
level3(processed);
}
void level1(int x) {
int modified = x * 3;
level2(modified);
}
void demonstrateCallStack() {
int initial = 5;
level1(initial);
// GDB Session:
// (gdb) break level3
// (gdb) run
// (gdb) backtrace
// #0 level3 (x=25) at examples.cpp:XX
// #1 level2 (x=15) at examples.cpp:XX
// #2 level1 (x=5) at examples.cpp:XX
// #3 demonstrateCallStack () at examples.cpp:XX
// #4 main () at examples.cpp:XX
//
// (gdb) frame 1
// (gdb) info locals
// processed = 15
// (gdb) info args
// x = 15
}
// ============================================================================
// EXAMPLE 5: Conditional Breakpoints
// ============================================================================
void processNumbers() {
for (int i = 0; i < 100; ++i) {
int value = i * i;
// We want to stop only when value > 1000
if (value > 1000) {
cout << "Large value at i=" << i << ": " << value << endl;
}
}
// GDB Session:
// (gdb) break examples.cpp:XX if value > 1000
// (gdb) run
// Breakpoint hit when i=32, value=1024
//
// Alternative: break when i equals specific value
// (gdb) break examples.cpp:XX if i == 50
}
// ============================================================================
// EXAMPLE 6: Watchpoints
// ============================================================================
void modifyVariable() {
int counter = 0;
for (int i = 0; i < 10; ++i) {
counter += i; // Watch this variable
}
cout << "Final counter: " << counter << endl;
// GDB Session:
// (gdb) break modifyVariable
// (gdb) run
// (gdb) next (until counter is declared)
// (gdb) watch counter
// Hardware watchpoint 2: counter
// (gdb) continue
// Hardware watchpoint 2: counter
// Old value = 0
// New value = 0
// (gdb) continue
// Old value = 0
// New value = 1
// ...
}
// ============================================================================
// EXAMPLE 7: Segmentation Fault Debugging
// ============================================================================
void causeSegfault(bool trigger = false) {
int* ptr = nullptr;
if (trigger) {
*ptr = 42; // This will crash!
} else {
cout << "No crash - trigger was false" << endl;
}
// GDB Session (when trigger=true):
// (gdb) run
// Program received signal SIGSEGV, Segmentation fault.
// 0x00000000004... in causeSegfault (trigger=true) at examples.cpp:XX
// XX *ptr = 42;
//
// (gdb) print ptr
// $1 = (int *) 0x0
// (gdb) backtrace
// Shows exact location of crash
}
// ============================================================================
// EXAMPLE 8: Class/Object Debugging
// ============================================================================
class Rectangle {
private:
double width;
double height;
std::string name;
public:
Rectangle(double w, double h, std::string n)
: width(w), height(h), name(std::move(n)) {}
double area() const { return width * height; }
double perimeter() const { return 2 * (width + height); }
void scale(double factor) {
width *= factor;
height *= factor;
}
};
void debugObjects() {
Rectangle rect(5.0, 3.0, "MyRect");
cout << "Area: " << rect.area() << endl;
rect.scale(2.0);
cout << "New area: " << rect.area() << endl;
// GDB Session:
// (gdb) break debugObjects
// (gdb) run
// (gdb) next (after construction)
//
// (gdb) print rect
// $1 = {width = 5, height = 3, name = "MyRect"}
//
// (gdb) print rect.width
// $2 = 5
//
// (gdb) call rect.area()
// $3 = 15
//
// (gdb) ptype rect
// type = class Rectangle {
// private:
// double width;
// double height;
// std::string name;
// public:
// Rectangle(double, double, std::string);
// double area(void) const;
// ...
// }
}
// ============================================================================
// EXAMPLE 9: Smart Pointer Debugging
// ============================================================================
void debugSmartPointers() {
auto uniquePtr = std::make_unique<int>(42);
auto sharedPtr1 = std::make_shared<std::string>("Hello");
auto sharedPtr2 = sharedPtr1;
*uniquePtr = 100;
*sharedPtr1 = "World";
cout << "unique: " << *uniquePtr << endl;
cout << "shared: " << *sharedPtr2 << endl;
// GDB Session:
// (gdb) break debugSmartPointers
// (gdb) run
// (gdb) next (until pointers are created)
//
// For unique_ptr:
// (gdb) print uniquePtr
// (gdb) print *uniquePtr._M_ptr
// $1 = 42
//
// For shared_ptr:
// (gdb) print sharedPtr1.use_count()
// (gdb) print *sharedPtr1._M_ptr
//
// With pretty printing:
// (gdb) set print pretty on
// (gdb) print uniquePtr
}
// ============================================================================
// EXAMPLE 10: Multi-threaded Debugging
// ============================================================================
std::mutex mtx;
int sharedCounter = 0;
void threadFunction(int id) {
for (int i = 0; i < 5; ++i) {
std::lock_guard<std::mutex> lock(mtx);
++sharedCounter;
cout << "Thread " << id << ": counter = " << sharedCounter << endl;
}
}
void debugThreads() {
std::thread t1(threadFunction, 1);
std::thread t2(threadFunction, 2);
t1.join();
t2.join();
cout << "Final counter: " << sharedCounter << endl;
// GDB Session:
// (gdb) break threadFunction
// (gdb) run
//
// (gdb) info threads
// Id Target Id Frame
// * 1 Thread 0x... "examples" main () at examples.cpp:XX
// 2 Thread 0x... "examples" threadFunction (id=1) at examples.cpp:XX
// 3 Thread 0x... "examples" threadFunction (id=2) at examples.cpp:XX
//
// (gdb) thread 2
// (gdb) backtrace
//
// (gdb) thread apply all bt
// Shows backtraces for all threads
//
// (gdb) set scheduler-locking on
// Only current thread runs
}
// ============================================================================
// EXAMPLE 11: Memory Examination
// ============================================================================
void examineMemory() {
char buffer[16] = "Hello, GDB!";
int numbers[4] = {0x41, 0x42, 0x43, 0x44}; // A, B, C, D in ASCII
cout << "Buffer: " << buffer << endl;
// GDB Session:
// (gdb) break examineMemory
// (gdb) run
// (gdb) next (until buffer is initialized)
//
// Examine as bytes (hex):
// (gdb) x/16xb buffer
// 0x...: 0x48 0x65 0x6c 0x6c 0x6f 0x2c 0x20 0x47
// 0x...: 0x44 0x42 0x21 0x00 0x00 0x00 0x00 0x00
//
// Examine as string:
// (gdb) x/s buffer
// 0x...: "Hello, GDB!"
//
// Examine as characters:
// (gdb) x/16cb buffer
// 'H' 'e' 'l' 'l' 'o' ',' ' ' 'G' 'D' 'B' '!' '\0' ...
//
// Examine integers:
// (gdb) x/4xw numbers
// 0x...: 0x00000041 0x00000042 0x00000043 0x00000044
}
// ============================================================================
// EXAMPLE 12: Debugging Loops
// ============================================================================
int sumArray(const int* arr, size_t size) {
int sum = 0;
for (size_t i = 0; i < size; ++i) {
sum += arr[i];
}
return sum;
}
void debugLoop() {
int data[] = {10, 20, 30, 40, 50};
int result = sumArray(data, 5);
cout << "Sum: " << result << endl;
// GDB Session:
// (gdb) break sumArray
// (gdb) run
//
// Step through loop iterations:
// (gdb) display i
// (gdb) display sum
// (gdb) next
// 1: i = 0
// 2: sum = 0
// (gdb) next
// 1: i = 0
// 2: sum = 10
// (gdb) next
// 1: i = 1
// 2: sum = 10
//
// Skip to end of loop:
// (gdb) until XX (line after loop)
}
// ============================================================================
// MAIN
// ============================================================================
int main(int argc, char* argv[]) {
cout << "╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ GDB DEBUGGING EXAMPLES ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
cout << "\n=== Example 1: Basic Variables ===" << endl;
calculateSum();
cout << "\n=== Example 2: Containers ===" << endl;
inspectContainers();
cout << "\n=== Example 3: Pointers ===" << endl;
debugPointers();
cout << "\n=== Example 4: Call Stack ===" << endl;
demonstrateCallStack();
cout << "\n=== Example 5: Conditional Breakpoints ===" << endl;
processNumbers();
cout << "\n=== Example 6: Watchpoints ===" << endl;
modifyVariable();
cout << "\n=== Example 7: Segfault (not triggered) ===" << endl;
causeSegfault(false); // Change to true to see segfault
cout << "\n=== Example 8: Objects ===" << endl;
debugObjects();
cout << "\n=== Example 9: Smart Pointers ===" << endl;
debugSmartPointers();
cout << "\n=== Example 10: Threads ===" << endl;
debugThreads();
cout << "\n=== Example 11: Memory Examination ===" << endl;
examineMemory();
cout << "\n=== Example 12: Loop Debugging ===" << endl;
debugLoop();
cout << "\n═══════════════════════════════════════════════════════════════" << endl;
cout << "To debug this program:" << endl;
cout << " g++ -g -O0 examples.cpp -o examples -pthread" << endl;
cout << " gdb ./examples" << endl;
cout << " (gdb) break main" << endl;
cout << " (gdb) run" << endl;
return 0;
}