Skip to content

Commit

Permalink
Merge pull request iovisor#2191 from iovisor/yhs_dev
Browse files Browse the repository at this point in the history
add btf func_info and line_info support
  • Loading branch information
yonghong-song committed Feb 10, 2019
2 parents de641d4 + 48ca781 commit b374be8
Show file tree
Hide file tree
Showing 13 changed files with 431 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/cc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ add_library(bpf-shared SHARED libbpf.c perf_reader.c ${libbpf_sources})
set_target_properties(bpf-shared PROPERTIES VERSION ${REVISION_LAST} SOVERSION 0)
set_target_properties(bpf-shared PROPERTIES OUTPUT_NAME bpf)

set(bcc_common_sources bpf_common.cc bpf_module.cc exported_files.cc)
set(bcc_common_sources bpf_common.cc bpf_module.cc bcc_btf.cc exported_files.cc)
if (${LLVM_PACKAGE_VERSION} VERSION_EQUAL 6 OR ${LLVM_PACKAGE_VERSION} VERSION_GREATER 6)
set(bcc_common_sources ${bcc_common_sources} bcc_debug.cc)
endif()
Expand Down
2 changes: 1 addition & 1 deletion src/cc/api/BPF.cc
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ StatusTuple BPF::load_func(const std::string& func_name, bpf_prog_type type,
else if (flag_ & DEBUG_BPF)
log_level = 1;

fd = bcc_prog_load(type, func_name.c_str(),
fd = bpf_module_->bcc_func_load(type, func_name.c_str(),
reinterpret_cast<struct bpf_insn*>(func_start), func_size,
bpf_module_->license(), bpf_module_->kern_version(),
log_level, nullptr, 0);
Expand Down
202 changes: 202 additions & 0 deletions src/cc/bcc_btf.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/*
* Copyright (c) 2019 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "bcc_btf.h"
#include <string.h>
#include "linux/btf.h"
#include "libbpf.h"
#include "libbpf/src/btf.h"
#include <vector>

namespace ebpf {

uint32_t BTFStringTable::addString(std::string S) {
// Check whether the string already exists.
for (auto &OffsetM : OffsetToIdMap) {
if (Table[OffsetM.second] == S)
return OffsetM.first;
}
// Not find, add to the string table.
uint32_t Offset = Size;
OffsetToIdMap[Offset] = Table.size();
Table.push_back(S);
Size += S.size() + 1;
return Offset;
}

BTF::~BTF() {
btf__free(btf_);
btf_ext__free(btf_ext_);
}

// The compiler doesn't have source code for remapped files.
// So we modify .BTF and .BTF.ext sections here to add these
// missing line source codes.
// The .BTF and .BTF.ext ELF section specification can be
// found at linux repo: linux/Documentation/bpf/btf.rst.
void BTF::adjust(uint8_t *btf_sec, uintptr_t btf_sec_size,
uint8_t *btf_ext_sec, uintptr_t btf_ext_sec_size,
std::map<std::string, std::string> &remapped_sources,
uint8_t **new_btf_sec, uintptr_t *new_btf_sec_size) {

// Line cache for remapped files
std::map<std::string, std::vector<std::string>> LineCaches;
for (auto it = remapped_sources.begin(); it != remapped_sources.end(); ++it) {
size_t FileBufSize = it->second.size();
std::vector<std::string> LineCache;

for (uint32_t start = 0, end = start; end < FileBufSize; end++) {
if (it->second[end] == '\n' || end == FileBufSize - 1 ||
(it->second[end] == '\r' && it->second[end + 1] == '\n')) {
// Not including the endline
LineCache.push_back(std::string(it->second.substr(start, end - start)));
if (it->second[end] == '\r')
end++;
start = end + 1;
}
}
LineCaches[it->first] = std::move(LineCache);
}

// Check the LineInfo table and add missing lines

struct btf_header *hdr = (struct btf_header *)btf_sec;
struct btf_ext_header *ehdr = (struct btf_ext_header *)btf_ext_sec;

char *strings = (char *)(btf_sec + hdr->hdr_len + hdr->str_off);
unsigned orig_strings_len = hdr->str_len;
unsigned *linfo_s = (unsigned *)(btf_ext_sec + ehdr->hdr_len + ehdr->line_info_off);
unsigned lrec_size = *linfo_s;
linfo_s++;
unsigned linfo_len = ehdr->line_info_len - 4;

// Go through all line info. For any line number whose line is in the LineCaches,
// Correct the line_off and record the corresponding source line in BTFStringTable,
// which later will be merged into .BTF string section.
BTFStringTable new_strings;
while (linfo_len) {
unsigned num_recs = linfo_s[1];
linfo_s += 2;
for (unsigned i = 0; i < num_recs; i++) {
struct bpf_line_info *linfo = (struct bpf_line_info *)linfo_s;
if (linfo->line_off == 0) {
for (auto it = LineCaches.begin(); it != LineCaches.end(); ++it) {
if (strcmp(strings + linfo->file_name_off, it->first.c_str()) == 0) {
unsigned line_num = BPF_LINE_INFO_LINE_NUM(linfo->line_col);
if (line_num > 0 && line_num <= it->second.size())
linfo->line_off = orig_strings_len + new_strings.addString(it->second[line_num - 1]);
}
}
}
linfo_s += lrec_size >> 2;
}
linfo_len -= 8 + num_recs * lrec_size;
}

// If any new source lines need to be recorded, do not touch the original section,
// allocate a new section. The original section is allocated through llvm infra.
if (new_strings.getSize() > 0) {
// LLVM generated .BTF layout always has type_sec followed by str_sec without holes,
// so we can just append the new strings to the end and adjust str_sec size.
unsigned tmp_sec_size = btf_sec_size + new_strings.getSize();
uint8_t *tmp_sec = new uint8_t[tmp_sec_size];
memcpy(tmp_sec, btf_sec, btf_sec_size);

struct btf_header *nhdr = (struct btf_header *)tmp_sec;
nhdr->str_len += new_strings.getSize();

// Populate new strings to the string table.
uint8_t *new_str = tmp_sec + nhdr->hdr_len + nhdr->str_off + orig_strings_len;
std::vector<std::string> &Table = new_strings.getTable();
for (unsigned i = 0; i < Table.size(); i++) {
strcpy((char *)new_str, Table[i].c_str());
new_str += Table[i].size() + 1;
}

*new_btf_sec = tmp_sec;
*new_btf_sec_size = tmp_sec_size;
}
}

int BTF::load(uint8_t *btf_sec, uintptr_t btf_sec_size,
uint8_t *btf_ext_sec, uintptr_t btf_ext_sec_size,
std::map<std::string, std::string> &remapped_sources) {
struct btf *btf;
struct btf_ext *btf_ext;
uint8_t *new_btf_sec = NULL;
uintptr_t new_btf_sec_size = 0;

adjust(btf_sec, btf_sec_size, btf_ext_sec, btf_ext_sec_size,
remapped_sources, &new_btf_sec, &new_btf_sec_size);

if (new_btf_sec) {
btf = btf__new(new_btf_sec, new_btf_sec_size);
delete new_btf_sec;
} else {
btf = btf__new(btf_sec, btf_sec_size);
}
if (!btf) {
fprintf(stderr, "Processing .BTF section failure\n");
return -1;
}

btf_ext = btf_ext__new(btf_ext_sec, btf_ext_sec_size);
if (!btf_ext) {
btf__free(btf);
fprintf(stderr, "Processing .BTF.ext section failure\n");
return -1;
}

btf_ = btf;
btf_ext_ = btf_ext;
return 0;
}

int BTF::get_fd() {
return btf__fd(btf_);
}

int BTF::get_btf_info(const char *fname,
void **func_info, unsigned *func_info_cnt,
unsigned *finfo_rec_size,
void **line_info, unsigned *line_info_cnt,
unsigned *linfo_rec_size) {
int ret;

*func_info = *line_info = NULL;
*func_info_cnt = *line_info_cnt = 0;

*finfo_rec_size = btf_ext__func_info_rec_size(btf_ext_);
*linfo_rec_size = btf_ext__line_info_rec_size(btf_ext_);

ret = btf_ext__reloc_func_info(btf_, btf_ext_, fname, 0,
func_info, func_info_cnt);
if (ret) {
fprintf(stderr, ".BTF.ext reloc func_info not successful\n");
return ret;
}

ret = btf_ext__reloc_line_info(btf_, btf_ext_, fname, 0,
line_info, line_info_cnt);
if (ret) {
fprintf(stderr, ".BTF.ext reloc line_info not successful\n");
return ret;
}

return 0;
}

} // namespace ebpf
70 changes: 70 additions & 0 deletions src/cc/bcc_btf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2019 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef BCC_BTF_H
#define BCC_BTF_H

#include <stdbool.h>
#include <stdint.h>
#include <string>
#include <map>
#include <vector>

struct btf;
struct btf_ext;

namespace ebpf {

class BTFStringTable {
private:
uint32_t Size;
std::map<uint32_t, uint32_t> OffsetToIdMap;
std::vector<std::string> Table;

public:
BTFStringTable(): Size(0) {}
uint32_t getSize() { return Size; }
std::vector<std::string> &getTable() { return Table; }
uint32_t addString(std::string Str);
};

class BTF {
public:
~BTF();
int load(uint8_t *btf_sec, uintptr_t btf_sec_size,
uint8_t *btf_ext_sec, uintptr_t btf_ext_sec_size,
std::map<std::string, std::string> &remapped_sources);
int get_fd();
int get_btf_info(const char *fname,
void **func_info, unsigned *func_info_cnt,
unsigned *finfo_rec_size,
void **line_info, unsigned *line_info_cnt,
unsigned *linfo_rec_size);

private:
void adjust(uint8_t *btf_sec, uintptr_t btf_sec_size,
uint8_t *btf_ext_sec, uintptr_t btf_ext_sec_size,
std::map<std::string, std::string> &remapped_sources,
uint8_t **new_btf_sec, uintptr_t *new_btf_sec_size);

private:
struct btf *btf_;
struct btf_ext *btf_ext_;
};

} // namespace ebpf

#endif
12 changes: 12 additions & 0 deletions src/cc/bpf_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,16 @@ int bpf_table_leaf_sscanf(void *program, size_t id, const char *buf, void *leaf)
return mod->table_leaf_scanf(id, buf, leaf);
}

int bcc_func_load(void *program, int prog_type, const char *name,
const struct bpf_insn *insns, int prog_len,
const char *license, unsigned kern_version,
int log_level, char *log_buf, unsigned log_buf_size) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return -1;
return mod->bcc_func_load(prog_type, name, insns, prog_len,
license, kern_version, log_level,
log_buf, log_buf_size);

}

}
6 changes: 6 additions & 0 deletions src/cc/bpf_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ int bpf_table_leaf_snprintf(void *program, size_t id, char *buf, size_t buflen,
int bpf_table_key_sscanf(void *program, size_t id, const char *buf, void *key);
int bpf_table_leaf_sscanf(void *program, size_t id, const char *buf, void *leaf);

struct bpf_insn;
int bcc_func_load(void *program, int prog_type, const char *name,
const struct bpf_insn *insns, int prog_len,
const char *license, unsigned kern_version,
int log_level, char *log_buf, unsigned log_buf_size);

#ifdef __cplusplus
}
#endif
Expand Down
Loading

0 comments on commit b374be8

Please sign in to comment.