ld-so-cache

Crates.iold-so-cache
lib.rsld-so-cache
version0.1.0
created_at2025-06-11 02:09:36.87137+00
updated_at2025-06-11 02:09:36.87137+00
descriptionA parser for glibc ld.so.cache files
homepage
repositoryhttps://gitlab.com/piperswe/ld-so-cache
max_upload_size
id1708006
size2,682,251
Piper McCorkle (piperswe)

documentation

README

ld-so-cache

A comprehensive Rust parser for Linux ld.so.cache files with 100% compatibility with ldconfig output.

Overview

The ld.so.cache file is used by the Linux dynamic linker to quickly locate shared libraries. This crate provides a complete parser that can read both legacy (ld.so-1.7.0) and modern (glibc) cache formats, extracting library names, paths, and hardware capability information.

Features

  • Complete Format Support: Handles both old (ld.so-1.7.0) and new (glibc) cache formats
  • Hardware Capabilities: Parses hardware capability flags including ISA levels and processor features
  • Extension Support: Handles cache extensions for future format enhancements
  • Error Resilience: Gracefully handles corrupted or truncated cache files
  • 100% ldconfig Compatibility: Produces identical output to ldconfig -p across many major distributions
  • Cross-Platform: Works on any platform that can read the cache files

Verified Compatibility

This parser has been tested against real cache files from:

  • Debian: Bookworm, Trixie
  • Ubuntu: Jammy (22.04), Noble (24.04), Questing (25.04)
  • AlmaLinux: 8, 9, 10
  • Red Hat: UBI 8

All tests show exact matches with ldconfig -p output.

Quick Start

Library Usage

use ld_so_cache::parsers::parse_ld_cache;
use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Parse the system's ld.so.cache file
    let data = fs::read("/etc/ld.so.cache")?;
    let cache = parse_ld_cache(&data)?;

    // Extract all library entries
    let entries = cache.get_entries()?;
    for entry in entries {
        println!("{} -> {}", entry.library_name, entry.library_path);
        
        // Check if it's an ELF library
        if entry.flags & 1 != 0 {
            println!("  ELF library");
        }
        
        // Display hardware capabilities if present
        if let Some(hwcap) = entry.hwcap {
            let isa_level = (hwcap >> 52) & 0x3ff;
            if isa_level > 0 {
                println!("  Requires ISA level: {}", isa_level);
            }
        }
    }
    
    Ok(())
}

Command Line Usage

The crate includes a CLI tool for inspecting cache files:

# Parse the system cache
ld-cache-parser

# Parse a specific cache file
ld-cache-parser -f /path/to/ld.so.cache

# Show detailed information including hardware capabilities
ld-cache-parser --verbose

# Output in JSON format
ld-cache-parser --format json

# Show only cache statistics
ld-cache-parser --stats

Cache Formats

Legacy Format (ld.so-1.7.0)

The old format provides basic library name to path mappings:

use ld_so_cache::OldFileEntry;

let entry = OldFileEntry {
    flags: 1,      // ELF library
    key: 0,        // Offset to library name
    value: 10,     // Offset to library path
};

Modern Format (glibc)

The new format includes hardware capabilities and extensions:

use ld_so_cache::NewFileEntry;

let entry = NewFileEntry {
    flags: 1,
    key: 0,
    value: 10,
    osversion_unused: 0,
    hwcap: 0x0020_0000_0000_1234, // Hardware capabilities
};

// Extract ISA level (bits 52-61)
let isa_level = (entry.hwcap >> 52) & 0x3ff;

// Check for extension flag (bit 62)
let has_extensions = entry.hwcap & (1u64 << 62) != 0;

// Get CPU features (bits 0-51)
let cpu_features = entry.hwcap & ((1u64 << 52) - 1);

Hardware Capabilities

The parser correctly decodes hardware capability information:

  • ISA Levels: x86-64-v2, x86-64-v3, etc. (bits 52-61)
  • Extension Flag: Indicates additional capability data (bit 62)
  • CPU Features: Various processor features like SSE, AVX (bits 0-51)
  • Architecture: i386, x86-64, libx32 from flags field

Error Handling

The library provides comprehensive error handling:

use ld_so_cache::{CacheError, parsers::parse_ld_cache};

match parse_ld_cache(&data) {
    Ok(cache) => {
        // Process cache entries
        match cache.get_entries() {
            Ok(entries) => println!("Found {} libraries", entries.len()),
            Err(CacheError::InvalidStringOffset(offset)) => {
                eprintln!("Corrupted string table at offset {}", offset);
            }
            Err(e) => eprintln!("Error extracting entries: {}", e),
        }
    }
    Err(CacheError::InvalidMagic) => {
        eprintln!("Not a valid ld.so.cache file");
    }
    Err(CacheError::TruncatedFile) => {
        eprintln!("Cache file is incomplete");
    }
    Err(e) => eprintln!("Parse error: {}", e),
}

JSON Output

The library supports JSON serialization with proper formatting:

{
  "library_name": "libc.so.6",
  "library_path": "/lib/x86_64-linux-gnu/libc.so.6",
  "flags": 769,
  "hwcap": "0x0000000000001000"
}

Installation

Add this to your Cargo.toml:

[dependencies]
ld-so-cache = "0.1"

Or install the CLI tool:

cargo install ld-so-cache

Documentation

Full API documentation is available at docs.rs.

The library includes extensive documentation with examples for all public APIs.

Testing

The crate includes comprehensive tests:

  • Unit Tests: All core parsing functionality
  • Integration Tests: Real cache files from multiple distributions
  • Compatibility Tests: Verification against ldconfig -p output
  • Documentation Tests: All code examples are tested

Run tests with:

cargo test

License

This project is licensed under the CC0 License - see the LICENSE.md file for details.

AI Disclaimer

This library was built with the help of Claude Code. This README was significantly written by Claude. I wanted to get this quickly built, so I took a shortcut.

Commit count: 14

cargo fmt