Sys-Ebpf

 view release on metacpan or  search on metacpan

lib/Sys/Ebpf/Elf/Parser.pm  view on Meta::CPAN

        = $elf->{e_shoff} + $elf->{e_shstrndx} * $elf->{e_shentsize};
    my $strtab_offset
        = unpack( 'Q', substr( $data, $strtab_section_offset + 24, 8 ) );

    # セクションヘッダとシンボルテーブルをパースするための追加処理
    $elf->{sections}
        = parse_sections( $data, $elf->{e_shoff}, $elf->{e_shnum},
        $elf->{e_shentsize}, $strtab_offset );
    $elf->{symbols}
        = parse_symbols( $data, $elf->{sections}, $elf->{e_shstrndx} );
    $elf->{relocations} = parse_relocations( $data, $elf->{sections} );
    return $elf;
}

# セクションヘッダをパースする
# args
#   data: ELFバイナリデータの文字列
#   shoff: セクションヘッダテーブルのオフセット
#   shnum: セクション数
#   shentsize: セクションヘッダのサイズ
#   strtab_offset: セクション名の文字列テーブルのオフセット

lib/Sys/Ebpf/Elf/Parser.pm  view on Meta::CPAN

    }

    return \@symbols;
}

# リロケーションテーブルをパースする
# args
#   data: ELFバイナリデータの文字列
#   sections: セクション情報の配列
# return
#   relocations: リロケーションテーブルのハッシュのリファレンス
sub parse_relocations {
    my ( $data, $sections ) = @_;
    my %relocations;

    for my $section (@$sections) {
        unless ( $section->{sh_type} == Sys::Ebpf::Elf::Constants::SHT_REL
            || $section->{sh_type} == Sys::Ebpf::Elf::Constants::SHT_RELA )
        {
            next;
        }
        my @relocation;
        my $sh_type         = $section->{sh_type};
        my $num_relocations = $section->{sh_size} / $section->{sh_entsize};

        for my $i ( 0 .. $num_relocations - 1 ) {
            my $offset = $section->{sh_offset} + $i * $section->{sh_entsize};
            my ( $r_offset, $r_info, $r_addend );

            # リロケーションテーブルのエントリをパース
            # 64ビットの場合はQで8バイトを読み込む(TODO: 32ビットの場合はLで4バイトを読み込む)
            if ( $sh_type == Sys::Ebpf::Elf::Constants::SHT_REL ) {
                ( $r_offset, $r_info )
                    = unpack( 'Q<Q<',
                    substr( $data, $offset, $section->{sh_entsize} ) );
                $r_addend = undef;
            }
            else {    # SHT_RELA
                ( $r_offset, $r_info, $r_addend )
                    = unpack( 'Q<Q<Q<',
                    substr( $data, $offset, $section->{sh_entsize} ) );
            }

            push @relocation,
                {
                sh_type  => $sh_type,
                r_offset => $r_offset,
                r_info   => $r_info,
                r_addend => $r_addend,
                };
        }
        $relocations{ $section->{sh_name} } = \@relocation;
    }

    return \%relocations;
}

sub is_bpf_machine_type {
    my ( $self, $e_machine ) = @_;
    return $e_machine == Sys::Ebpf::Elf::Constants::EM_BPF;
}

sub find_section {
    my ( $sections, $name ) = @_;
    return ( grep { $_->{sh_name} eq $name } @$sections )[0];

lib/Sys/Ebpf/Loader.pm  view on Meta::CPAN


# リロケーションを適用
# args:
#   prob_section: プログラムセクション
#   reloc_sections: リロケーションセクション
#   elf: ELFデータ
#   map_hash_ref: マップデータのリファレンス
# r_offsetを使って、修正すべき命令(インストラクション)をkprobe/sys_execveセクション内から特定します。
# r_infoからシンボルインデックスを取得し、そのシンボルのアドレスをシンボルテーブル(.symtab)から取得します。
# 修正すべきインストラクションに、シンボルのアドレスを適用して、正しいマップへの参照に書き換えます。
sub apply_map_relocations {
    my ( $self, $prob_section, $reloc_sections, $elf, $map_hash_ref ) = @_;
    my $symbols_section = $elf->{symbols};
    for my $reloc_section (@$reloc_sections) {
        my $r_info = $reloc_section->{r_info};
        my $r_offset
            = $reloc_section->{r_offset} + $prob_section->{sh_offset};

        my $sym_index  = $r_info >> 32;           # シンボルインデックスを取得
        my $reloc_type = $r_info & 0xFFFFFFFF;    # リロケーションタイプを取得

        # シンボルテーブルからrelocation対象になり得るシンボル名を取得
        my $symbol = $symbols_section->[$sym_index] // undef;
        if ( !$symbol ) {
            print "Symbol Table not found for index: $sym_index\n";
            next;
        }
        my $sym_name = $symbol->{st_name};
        if ( $symbol->{st_shndx} == 0 ) {
            print "Symbol Name Table not found for index: $sym_index\n";
            next;
        }

lib/Sys/Ebpf/Loader.pm  view on Meta::CPAN

        my $map_name     = $map->{map_name};
        my $map_instance = Sys::Ebpf::Map->create($map);
        my $map_fd       = $map_instance->{map_fd};
        if ( $map_fd < 0 ) {
            die "Failed to load BPF map: $map_name (FD: $map_fd})\n";
        }
        $map_collection{$map_name} = $map_instance;
    }

    # リロケーションを適用
    my $reloc_section = $bpfelf->{relocations}{ ".rel" . $section_name };
    my $prob_section
        = find_symbol_table_from_name( $bpfelf->{sections}, $section_name );
    if ( defined $reloc_section ) {
        $self->apply_map_relocations( $prob_section, $reloc_section, $bpfelf,
            \%map_collection );
    }

    # todo: bpfprobが複数あるケースにも対応する
    # BPF プログラムをロード
    my $prog_fd = $self->load_bpf_program_from_elf($section_name);

    return ( \%map_collection, $prog_fd );
}



( run in 0.988 second using v1.01-cache-2.11-cpan-71847e10f99 )