Locating Segmentation Faults with GDB and Core Dumps
Ensure the source code is compiled with the -g flag to embed debugging symbols.
- Check core file size limit: Run
ulimit -c. A return value of 0 means core dumps are disabled;unlimitedmeans no size restriction. Useulimit -ato view all resource limits. - Enable unlimited core size:
ulimit -c unlimited - Check core file path:
cat /proc/sys/kernel/core_pattern - Modify core file path:
echo /tmp/coredump-%e-%s-%u-%g-%p-%t > /proc/sys/kernel/core_pattern>redirects standard output to a file (overwrite).<uses file content as standard input.>>appends standard output to a file.2>redirects standard error to a file.2>&1merges standard error into standard output.
- Analyze core file:
gdb <executable_path> <core_file_path>(e.g.,gdb ./my_app /tmp/coredump-my_app-11-0-0-2215-1706064035) - View call stack: Type
btorbacktracein GDB.
GDB Debugging Session Commands
Always compile with the -g flag for debugging symbols.
Starting GDB
gdb <executable>: Launch GDB and load the binary.gdb --args <executable> <arg1> <arg2>: Launch GDB and pass command-line arguments to the binary.
Breakpoints
break main # Set breakpoint at function entry
break 42 # Set breakpoint at line 42 in current file
break app.c:42 # Set breakpoint at line 42 in app.c
break app.c:main # Set breakpoint at main in app.c
Execution Control
run (r) # Start program execution
run arg1 arg2 # Start execution with arguments
continue (c) # Continue execution from current breakpoint
next (n) # Step over (execute next line, do not enter functions)
step (s) # Step into (execute next line, enter functions)
Inspecting Variables and Stack
print var_name # Print variable value
info locals # Display local variables in current frame
backtrace (bt) # Display call stack
frame 2 # Switch to stack frame 2
up / down # Navigate up/down the call stack
Memory Inspection
x/<format> <addr> # Examine memory. e.g., x/x 0x400800 shows hex content
Debugging Information
list (l) # Display source code around current line
info breakpoints # Show current breakpoints
info threads # Show current threads
info registers # Show CPU registers
Altering Program State
set var_name = value: Modify a variable's value at runtime.return expr: Force the current function to return the specified expression.
Exiting
quit (q) # Terminate GDB
Note: If the call stack is corrupted and bt provides no useful information, insert debug printf statements to narrow down the crash location, paying close attention to pointer arithmetic and array boundaries.
Static (.a) vs Dynamic (.so) Libraries
Source Files
/* main.c */
#include <stdio.h>
#include "math_ops.h"
int main() {
int x = 10, y = 4;
int result = add_values(x, y);
printf("Calculation Result: %d\n", result);
return 0;
}
/* math_ops.h */
#ifndef MATH_OPS_H
#define MATH_OPS_H
int add_values(int a, int b);
#endif
/* math_ops.c */
#include "math_ops.h"
int add_values(int a, int b) {
return a + b;
}
Creating and Using Static Libraries
- Compile the source into an object file:
gcc -c math_ops.c -o math_ops.o - Archive the object file into a static library using
ar:ar rcs libmath_ops.a math_ops.o - Link the main program against the static library (
-Lspecifies the library path,-lspecifies the library name omittingliband.a):gcc main.c -L. -lmath_ops -o main_static - Execute:
./main_static
Static libraries are linked at compile time and bundled into the final executable, increasing its file size.
Creating and Using Dynamic Libraries
- Compile into a shared library (
-sharedcreates a shared object,-fPICgenerates Position Independent Code):gcc -shared -fPIC -o libmath_ops.so math_ops.c - Verify exported symbols using
nm:nm libmath_ops.so - Link the main program:
gcc main.c -L. -lmath_ops -o main_dynamic - Execute:
./main_dynamic
If you encountererror while loading shared libraries: libmath_ops.so: cannot open shared object file, it means the runtime linker cannot find the library. - Resolve by updating the library search path:
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
Dynamic libraries are linked at runtime, keeping the executable small, but they require the library to be present on the target system.
ARM Assembly Basics
- Load (Read Memory):
LDR R0, [R1, #4]— Reads 4 bytes from addressR1 + 4intoR0. - Store (Write Memory):
STR R0, [R1, #4]— Writes 4 bytes fromR0to addressR1 + 4. - Arithmetic:
ADD R0, R1, R2—R0 = R1 + R2ADD R0, R0, #1—R0 = R0 + 1SUB R0, R1, R2—R0 = R1 - R2SUB R0, R0, #1—R0 = R0 - 1
- Compare:
CMP R0, R1— Subtracts R1 from R0 and updates the Program Status Register (PSR) flags. - Branching:
B label— Unconditional jump to label.BL label— Branch with Link; stores the return address in the Link Register (LR) before jumping.
Makefile Essentials
Syntax and Execution
target: prerequisites
recipe
A recipe executes if a prerequisite does not exist, or if a prerequisite's modification timestamp is newer than the target's timestamp.
Automatic Variables
$@: The target file.$^: All prerequisite files.$<: The first prerequisite file.
Phony Targets
.PHONY: clean ensures make clean runs even if a file named clean exists.
Variable Assignment
IMM := val: Immediate assignment; value is determined at definition.DEL = val: Deferred assignment; value is determined when the variable is used.?= val: Conditional assignment; only sets the value if the variable is not already defined.+= val: Append; behaves as immediate or deferred based on the variable's initial definition.
Common Functions
$(foreach var, list, text): Iterates overlist, replacingvarintext.$(filter pattern, text): Returns items intextmatchingpattern.$(filter-out pattern, text): Returns items intextnot matchingpattern.$(wildcard pattern): Returns existing files matchingpattern.$(patsubst pattern, replacement, text): Replacespatternwithreplacementintext.
Dependency Generation
gcc -M src.c: Print all dependencies to stdout.gcc -M -MF src.d src.c: Write dependencies tosrc.d.gcc -c -o src.o src.c -MD -MF src.d: Compile and generate dependencies simultaneously.
Files starting with a dot (e.g., .src.o.d) are hidden in Linux.
Passing macros: EXTRA_CFLAGS := -DDEBUG
Makefile Example
OBJS = core.o app.o
DEP_FILES := $(patsubst %, %.d, $(OBJS))
DEP_FILES := $(wildcard $(DEP_FILES))
my_program: $(OBJS)
gcc -o $@ $^
@echo $(DEP_FILES)
core.o: core.c core.h
%.o: %.c
gcc -c -o $@ $< -MD -MF .$@.d
ifneq ($(DEP_FILES), )
include $(DEP_FILES)
endif
clean:
rm -f *.o my_program
C/C++ Concepts
Struct Assignment
Direct assignment of structs is valid in C/C++. The compiler handles member-wise copying.
struct Record {
int id;
int score;
};
struct Record r1;
struct Record r2 = {101, 95};
r1 = r2; // Valid
Returning Pointers to Local Variables
Returning a pointer to a local variable leads to undefined behavior (often a segmentation fault) because the stack frame is destroyed when the function returns.
int* generate_array() {
int arr[5] = {1, 2, 3, 4, 5};
return arr; // ERROR: Returning local stack memory
}
int main() {
int* ptr = generate_array();
// Accessing ptr[0] causes a segfault
return 0;
}
Data Sizes and Bandwidth
- 8 bits = 1 Byte
- 1024 Bytes = 1 KB
- 1024 KB = 1 MB
- 1024 MB = 1 GB
Bandwidth conversion: 300 Mbps (Megabits per second) = 300 / 8 = 37.5 MB/s (Megabytes per second).
YUV formats:
YUV 4:2:0: Full Y sampling, half U sampling, quarter V sampling. Size = 1.5 bytes per pixel.
YUV 4:4:4: Full sampling for all components. Size = 3 bytes per pixel.
A 1080p frame (1920x1080) at YUV4:4:4 is approximately 6.2 MB. At 30 FPS, the data rate is roughly 186 MB/s (~0.18 GB/s).
Networking Basics
Local Area Network (LAN) devices access the internet through a router. The router possesses the public IP address. When a LAN device sends a request to an external server, the router maps the internal IP to its public IP and an assigned port (NAT). Two devices on separate LANs cannot communicate directly; they require a relay server or NAT traversal techniques (like STUN) to establish a connection.
MQTT Client Workflow
- Establish connection with the MQTT broker.
- Subscribe to desired topics.
- Enter main loop:
- Read incoming packets:
read_mqtt_packet(&buffer, len, timeout) - Process the received packet.
- Send periodic Ping requests to keep the connection alive.
- Read incoming packets:
Running LVGL on Ubuntu
To validate LVGL (Light and Versatile Graphics Library) natively on Linux:
# Install dependencies
sudo apt update
sudo apt install build-essential git cmake xorg-dev libglu1-mesa-dev
# Clone the repository
git clone https://github.com/lvgl/lvgl.git
cd lvgl
# Build using CMake
mkdir build && cd build
cmake ..
make
# Run the benchmark example
cd ../lv_examples/lv_demo_benchmark
./lv_demo_benchmark
Protocol Buffers Implementation
Define the message structure in a .proto file:
syntax = "proto3";
message Employee {
int32 emp_id = 1;
string full_name = 2;
string department = 3;
}
Use the protoc compiler to generate C++ headers and sources (e.g., employee.pb.h, employee.pb.cc).
Sender: Serialization
#include <fstream>
#include "employee.pb.h"
int main() {
Employee emp;
emp.set_emp_id(42);
emp.set_full_name("Jane Doe");
emp.set_department("Engineering");
std::string serialized;
emp.SerializeToString(&serialized);
std::ofstream out("emp_data.bin", std::ios::binary);
out.write(serialized.data(), serialized.size());
out.close();
return 0;
}
Receiver: Deserialization
#include <iostream>
#include <fstream>
#include "employee.pb.h"
int main() {
std::ifstream in("emp_data.bin", std::ios::binary);
std::string serialized((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
in.close();
Employee emp;
emp.ParseFromString(serialized);
std::cout << "ID: " << emp.emp_id() << "\n"
<< "Name: " << emp.full_name() << "\n"
<< "Dept: " << emp.department() << std::endl;
return 0;
}