Essential Operating System Concepts and Debugging Techniques

GDB Debuggging Commands and Advanced Debugging Scenarios

Core GDB Operations

GDB requires executables compiled with debugging symbols using the -g flag during compilation:

gcc -g source.c -o executable

Essential Commands

  • quit - Terminate debugging session
  • list - Display source code segments
    • list 5,10 shows lines 5 through 10
    • list file.c:5,10 specifies source file
    • list function_name displays code around function
  • reverse-search pattern - Search backward for string pattern
  • run - Execute program from beginning
  • help command - Access documentation
  • break - Set breakpoints
    • break 15 at line number
    • break function at function entry
    • break location if condition for conditional breakpoints
  • watch expression - Halt when expression value changes
  • next - Execute next statement (treats functions as single steps)
  • step - Enter function calls and execute line-by-line

Conditional Breakpoints

Breakpoints can be configured to trigger only when specific conditions are met:

break function_name if variable > threshold

Multi-process Debugging

Debug child or parent processes selectively:

set follow-fork-mode child
set follow-fork-mode parent

Byte Order Representation

Little Endian Architecture

Stores least significant bytes at lower memory addresses. Common in x86 systems and many ARM processors.

Big Endian Architecture

Places most significant bytes at lower memory addresses. Used in network protocols and some embedded systems.

Detection Method

Union-based approach exploits memory layout:

int check_endianness() {
    union {
        uint32_t num;
        uint8_t byte;
    } detector;
    
    detector.num = 1;
    return (detector.byte == 1) ? 1 : 0;  // Returns 1 for little endian
}

Network communication between different architectures requires byte order conversion. Same-architecture communication typically doesn't require conversion.

Process Scheduling Mechanisms

Primary Algorithms

  1. First-Come First-Served (FCFS) - Processes executed in arrival order
  2. Shortest Job First (SJF) - Prioritizes processes with shortest estimated runtime
  3. Priority Scheduling - Selects highest priority processes
  4. Round Robin - Allocates fixed time slices cyclically
  5. Multilevel Feedback Queue - Combines multiple scheduling strategies

Scheduling Characteristics

  • Preemptive: Allows forced suspension of running processes
  • Non-preemptive: Processes run until completion or blocking

Memory Management Architecture

Physical Memory Hierarchy

Four-tier organization from fastest to slowest:

  1. Registers
  2. Cache memory
  3. Main RAM
  4. Disk storage

Memory manager tracks usage, allocates resources during process execution, and reclaims memory upon termination.

Virtual Memory System

Each process receives independent virtual address space. Translation between virtual and physical addresses occurs through page tables.

Privilege Levels in Linux

Execution Modes

  • Kernel Mode: Full system access with unrestricted instruction execution
  • User Mode: Limited access to protected system resources

Transition Triggers

Three mechanisms initiate kernel mode entry:

  1. System calls (voluntary)
  2. Exceptions (involuntary)
  3. Hardware interrupts (involuntary)

Security isolation prevents user programs from executing privileged operations like memory clearing or clock manipulation.

LRU Cache Implementation

Algorithm Purpose

Least Recently Used eviction strategy removes infrequently accessed items from cache.

Data Structure Design

Combines doubly-linked list with hash map for O(1) operations:

class CacheManager {
private:
    std::list<std::pair<int, int>> data_chain;
    std::unordered_map<int, std::list<std::pair<int, int>>::iterator> index_map;
    int max_capacity;
    
public:
    CacheManager(int size) : max_capacity(size) {}
    
    int retrieve(int key) {
        if (index_map.find(key) != index_map.end()) {
            auto record = *index_map[key];
            data_chain.erase(index_map[key]);
            index_map.erase(key);
            data_chain.push_front(record);
            index_map[key] = data_chain.begin();
            return record.second;
        }
        return -1;
    }
    
    void insert(int key, int value) {
        if (index_map.find(key) != index_map.end()) {
            data_chain.erase(index_map[key]);
            index_map.erase(key);
        } else if (data_chain.size() >= max_capacity) {
            auto last_record = data_chain.back();
            index_map.erase(last_record.first);
            data_chain.pop_back();
        }
        
        data_chain.push_front({key, value});
        index_map[key] = data_chain.begin();
    }
};

Tags: operating-system debugging gdb memory-management byte-order

Posted on Mon, 21 Sep 2026 16:35:55 +0000 by FrostedFlakes