Help us understand the problem. What is going on with this article?

gimli-rs - 死は確実にして業は成り難し。何を迷う?

More than 1 year has passed since last update.

冒頭のやつは指輪物語ですね、これがやりたかっただけです。

gimli-rsというDWARFを扱うためのライブラリをちょこっと紹介します。

DWARFというのはデバッグ情報のフォーマットのとこで、 詳しいことは デバッグ情報の歩き方 というすばらしいエントリがあるのでこっちみてください。DWARFをいい感じに操作したいとなると今までは選択肢はlibdwarfとか使ってCでやるしかなかったんですが、Rustでいい感じのやつが出てきたので選択肢が増えました。

Gimliは,

  • ゼロコピー
  • 遅延評価(.debug_infoとかがいっぱいDIEもってるとめっちゃでかいので嬉しいやつ)
  • クロスプラットフォーム(とりあえずELF/Mach-O、もしかしたらPEも使えるかもしれない)

といった感じで謳っています。

でまあ利用例だと

とかあって、俺がわざわざ雑なの書くよりこのへんのcrate読んだほうがいいですね。。dwprodとか地味に便利(ほんとか?)で、これまで readelf -wi hello| grep DW_AT_producer とかやってたのがいい感じになりました。

ちょっと触ってみる

なにもコード書かないのも運営に怒られそうなので(?)、しょぼいdwprodもどきを書いてどんな感じかみてみましょう。

こんなかんじのコードを書いてみます。

extern crate fallible_iterator;
extern crate gimli;
extern crate failure;

use std::fs::File;
use std::io::Read;

use failure::Error;

fn get_section(section_name: &str) -> Result<Vec<u8>, Error> {
    let mut file = File::open(section_name)?;
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)?;
    Ok(buffer)
}

fn run() -> Result<(), Error> {
    let endian = gimli::LittleEndian;

    let info_dump = get_section(".debug_info").unwrap();
    let debug_info = gimli::DebugInfo::new(&info_dump, endian);
    let abbrev_dump = get_section(".debug_abbrev").unwrap();
    let debug_abbrev = gimli::DebugAbbrev::new(&abbrev_dump, endian);

    let mut iter = debug_info.units();
    while let Some(unit) = iter.next().expect("Should parse compilation unit") {
        let abbrevs = try!(unit.abbreviations(&debug_abbrev));

        let mut entries = unit.entries(&abbrevs);
        while let Some((_, entry)) = try!(entries.next_dfs()) {
            let mut attrs = entry.attrs();
            while let Some(attr) = attrs.next().unwrap() {
                if attr.name() == gimli::DW_AT_producer {
                    println!("Found a producer: {:?}", attr.value());
                    return Ok(()); // いっぱい出てくるから手抜きしてさっさと返しちゃいます
                }
            }
        }
    }
    Ok(())
}

fn main() {
    match run() {
        Ok(()) => {},
        Err(err) => println!("error: {}", err)
    }
}

てきとーにobjcopy使ってdebuginfoとdebugabbrevをdumpしておきましょう。

$ objcopy --dump-section .debug_abbrev=.debug_abbrev target/debug/producer
$ objcopy --dump-section .debug_info=.debug_info target/debug/producer

実行するとこんな感じのよくわからないのが出てきます。

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/producer`
Found a producer: DebugStrRef(DebugStrOffset(0))

これは .debug_str セクションというまた別のセクションへの参照とオフセット情報を返しているので、場所を教えているだけです。ここから .debug_str を探してちゃんとやるとdwprodみたいな感じにできるはず…たぶん。

そういえばdmdとか-gつけても .debug_str 吐かないやついるんですけど地味に困りますね。

こんなところでお終いです。みなさんもgimliを使っていろいろやっていきましょう。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away