forked from Mirror/frr
Merge pull request #8353 from opensourcerouting/llvm-20210327
This commit is contained in:
commit
c99313762a
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -30,6 +30,7 @@
|
|||
/libtool.orig
|
||||
/changelog-auto
|
||||
/test-driver
|
||||
/test-suite.log
|
||||
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
|
@ -57,6 +58,7 @@
|
|||
*.pb.cc
|
||||
*_clippy.c
|
||||
*.bc
|
||||
*.ll
|
||||
*.cg.json
|
||||
*.cg.dot
|
||||
*.cg.svg
|
||||
|
|
|
@ -315,10 +315,12 @@ struct prefix_sg {
|
|||
#ifndef __cplusplus
|
||||
#define prefixtype(uname, typename, fieldname) \
|
||||
typename *fieldname;
|
||||
#define TRANSPARENT_UNION __attribute__((transparent_union))
|
||||
#else
|
||||
#define prefixtype(uname, typename, fieldname) \
|
||||
typename *fieldname; \
|
||||
uname(typename *x) { this->fieldname = x; }
|
||||
#define TRANSPARENT_UNION
|
||||
#endif
|
||||
|
||||
union prefixptr {
|
||||
|
@ -328,7 +330,7 @@ union prefixptr {
|
|||
prefixtype(prefixptr, struct prefix_evpn, evp)
|
||||
prefixtype(prefixptr, struct prefix_fs, fs)
|
||||
prefixtype(prefixptr, struct prefix_rd, rd)
|
||||
} __attribute__((transparent_union));
|
||||
} TRANSPARENT_UNION;
|
||||
|
||||
union prefixconstptr {
|
||||
prefixtype(prefixconstptr, const struct prefix, p)
|
||||
|
@ -337,7 +339,10 @@ union prefixconstptr {
|
|||
prefixtype(prefixconstptr, const struct prefix_evpn, evp)
|
||||
prefixtype(prefixconstptr, const struct prefix_fs, fs)
|
||||
prefixtype(prefixconstptr, const struct prefix_rd, rd)
|
||||
} __attribute__((transparent_union));
|
||||
} TRANSPARENT_UNION;
|
||||
|
||||
#undef prefixtype
|
||||
#undef TRANSPARENT_UNION
|
||||
|
||||
#ifndef INET_ADDRSTRLEN
|
||||
#define INET_ADDRSTRLEN 16
|
||||
|
|
1
tools/.gitignore
vendored
1
tools/.gitignore
vendored
|
@ -8,3 +8,4 @@
|
|||
/frrcommon.sh
|
||||
/frr.service
|
||||
/frr@.service
|
||||
/frr-llvm-cg
|
||||
|
|
|
@ -50,11 +50,15 @@
|
|||
|
||||
#include <json-c/json.h>
|
||||
|
||||
#include "frr-llvm-debuginfo.h"
|
||||
|
||||
/* if you want to use this without the special FRRouting defines,
|
||||
* remove the following #define
|
||||
*/
|
||||
#define FRR_SPECIFIC
|
||||
|
||||
static struct dbginfo *dbginfo;
|
||||
|
||||
static void dbgloc_add(struct json_object *jsobj, LLVMValueRef obj)
|
||||
{
|
||||
unsigned file_len = 0;
|
||||
|
@ -85,6 +89,70 @@ static struct json_object *js_get_or_make(struct json_object *parent,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool try_struct_fptr(struct json_object *js_call, LLVMValueRef gep,
|
||||
const char *prefix)
|
||||
{
|
||||
unsigned long long val = 0;
|
||||
bool ret = false;
|
||||
LLVMTypeRef ptrtype = LLVMTypeOf(LLVMGetOperand(gep, 0));
|
||||
LLVMValueRef idx;
|
||||
|
||||
/* middle steps like struct a -> struct b a_member; -> fptr */
|
||||
for (int i = 1; ptrtype && i < LLVMGetNumOperands(gep) - 1; i++) {
|
||||
if (LLVMGetTypeKind(ptrtype) == LLVMPointerTypeKind
|
||||
|| LLVMGetTypeKind(ptrtype) == LLVMArrayTypeKind
|
||||
|| LLVMGetTypeKind(ptrtype) == LLVMVectorTypeKind) {
|
||||
ptrtype = LLVMGetElementType(ptrtype);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (LLVMGetTypeKind(ptrtype) != LLVMStructTypeKind)
|
||||
return false;
|
||||
|
||||
idx = LLVMGetOperand(gep, i);
|
||||
if (!LLVMIsConstant(idx))
|
||||
return false;
|
||||
val = LLVMConstIntGetZExtValue(idx);
|
||||
|
||||
unsigned n = LLVMGetNumContainedTypes(ptrtype);
|
||||
LLVMTypeRef arr[n];
|
||||
|
||||
if (val > n)
|
||||
return false;
|
||||
|
||||
LLVMGetSubtypes(ptrtype, arr);
|
||||
ptrtype = arr[val];
|
||||
}
|
||||
|
||||
if (!ptrtype)
|
||||
return false;
|
||||
|
||||
idx = LLVMGetOperand(gep, LLVMGetNumOperands(gep) - 1);
|
||||
if (!LLVMIsConstant(idx))
|
||||
return false;
|
||||
|
||||
val = LLVMConstIntGetZExtValue(idx);
|
||||
|
||||
char *sname = NULL, *mname = NULL;
|
||||
|
||||
if (dbginfo_struct_member(dbginfo, ptrtype, val, &sname, &mname)) {
|
||||
fprintf(stderr, "%s: call to struct %s->%s\n", prefix, sname,
|
||||
mname);
|
||||
|
||||
json_object_object_add(js_call, "type",
|
||||
json_object_new_string("struct_memb"));
|
||||
json_object_object_add(js_call, "struct",
|
||||
json_object_new_string(sname));
|
||||
json_object_object_add(js_call, "member",
|
||||
json_object_new_string(mname));
|
||||
ret = true;
|
||||
}
|
||||
free(sname);
|
||||
free(mname);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool details_fptr_vars = false;
|
||||
static bool details_fptr_consts = true;
|
||||
|
||||
|
@ -175,6 +243,34 @@ static void walk_const_fptrs(struct json_object *js_call, LLVMValueRef value,
|
|||
prefix, hdr_written);
|
||||
return;
|
||||
|
||||
case LLVMConstantExprValueKind:
|
||||
switch (LLVMGetConstOpcode(value)) {
|
||||
case LLVMGetElementPtr:
|
||||
if (try_struct_fptr(js_call, value, prefix)) {
|
||||
*hdr_written = true;
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"%s: calls function pointer from unhandled const GEP\n",
|
||||
prefix);
|
||||
*hdr_written = true;
|
||||
/* fallthru */
|
||||
default:
|
||||
/* to help the user / development */
|
||||
if (!*hdr_written) {
|
||||
fprintf(stderr,
|
||||
"%s: calls function pointer from constexpr\n",
|
||||
prefix);
|
||||
*hdr_written = true;
|
||||
}
|
||||
dump = LLVMPrintValueToString(value);
|
||||
fprintf(stderr, "%s- [opcode=%d] %s\n", prefix,
|
||||
LLVMGetConstOpcode(value), dump);
|
||||
LLVMDisposeMessage(dump);
|
||||
}
|
||||
return;
|
||||
|
||||
default:
|
||||
/* to help the user / development */
|
||||
if (!*hdr_written) {
|
||||
|
@ -197,7 +293,7 @@ static void walk_const_fptrs(struct json_object *js_call, LLVMValueRef value,
|
|||
#ifdef FRR_SPECIFIC
|
||||
static bool is_thread_sched(const char *name, size_t len)
|
||||
{
|
||||
#define thread_prefix "funcname_"
|
||||
#define thread_prefix "_"
|
||||
static const char *const names[] = {
|
||||
thread_prefix "thread_add_read_write",
|
||||
thread_prefix "thread_add_timer",
|
||||
|
@ -218,6 +314,225 @@ static bool is_thread_sched(const char *name, size_t len)
|
|||
}
|
||||
#endif
|
||||
|
||||
static bool _check_val(bool cond, const char *text, LLVMValueRef dumpval)
|
||||
{
|
||||
if (cond)
|
||||
return true;
|
||||
|
||||
char *dump = LLVMPrintValueToString(dumpval);
|
||||
fprintf(stderr, "check failed: %s\ndump:\n\t%s\n", text, dump);
|
||||
LLVMDisposeMessage(dump);
|
||||
return false;
|
||||
}
|
||||
|
||||
#define check_val(cond, dump) \
|
||||
if (!_check_val(cond, #cond, dump)) \
|
||||
return;
|
||||
|
||||
static char *get_string(LLVMValueRef value)
|
||||
{
|
||||
if (!LLVMIsAConstant(value))
|
||||
return strdup("!NOT-A-CONST");
|
||||
|
||||
if (LLVMGetValueKind(value) == LLVMConstantExprValueKind
|
||||
&& LLVMGetConstOpcode(value) == LLVMGetElementPtr) {
|
||||
value = LLVMGetOperand(value, 0);
|
||||
|
||||
if (!LLVMIsAConstant(value))
|
||||
return strdup("!NOT-A-CONST-2");
|
||||
}
|
||||
|
||||
if (LLVMIsAGlobalVariable(value))
|
||||
value = LLVMGetInitializer(value);
|
||||
|
||||
size_t len = 0;
|
||||
const char *sval = LLVMGetAsString(value, &len);
|
||||
|
||||
return strndup(sval, len);
|
||||
}
|
||||
|
||||
static void handle_yang_module(struct json_object *js_special,
|
||||
LLVMValueRef yang_mod)
|
||||
{
|
||||
check_val(LLVMIsAGlobalVariable(yang_mod), yang_mod);
|
||||
|
||||
LLVMValueRef value;
|
||||
|
||||
value = LLVMGetInitializer(yang_mod);
|
||||
LLVMValueKind kind = LLVMGetValueKind(value);
|
||||
|
||||
check_val(kind == LLVMConstantStructValueKind, value);
|
||||
|
||||
size_t var_len = 0;
|
||||
const char *var_name = LLVMGetValueName2(yang_mod, &var_len);
|
||||
char buf_name[var_len + 1];
|
||||
|
||||
memcpy(buf_name, var_name, var_len);
|
||||
buf_name[var_len] = '\0';
|
||||
|
||||
struct json_object *js_yang, *js_yangmod, *js_items;
|
||||
|
||||
js_yang = js_get_or_make(js_special, "yang", json_object_new_object);
|
||||
js_yangmod = js_get_or_make(js_yang, buf_name, json_object_new_object);
|
||||
js_items = js_get_or_make(js_yangmod, "items", json_object_new_array);
|
||||
|
||||
char *mod_name = get_string(LLVMGetOperand(value, 0));
|
||||
json_object_object_add(js_yangmod, "name",
|
||||
json_object_new_string(mod_name));
|
||||
free(mod_name);
|
||||
|
||||
value = LLVMGetOperand(value, 1);
|
||||
kind = LLVMGetValueKind(value);
|
||||
check_val(kind == LLVMConstantArrayValueKind, value);
|
||||
|
||||
unsigned len = LLVMGetArrayLength(LLVMTypeOf(value));
|
||||
|
||||
for (unsigned i = 0; i < len - 1; i++) {
|
||||
struct json_object *js_item, *js_cbs;
|
||||
LLVMValueRef item = LLVMGetOperand(value, i);
|
||||
char *xpath = get_string(LLVMGetOperand(item, 0));
|
||||
|
||||
js_item = json_object_new_object();
|
||||
json_object_array_add(js_items, js_item);
|
||||
|
||||
json_object_object_add(js_item, "xpath",
|
||||
json_object_new_string(xpath));
|
||||
js_cbs = js_get_or_make(js_item, "cbs", json_object_new_object);
|
||||
|
||||
free(xpath);
|
||||
|
||||
LLVMValueRef cbs = LLVMGetOperand(item, 1);
|
||||
|
||||
check_val(LLVMGetValueKind(cbs) == LLVMConstantStructValueKind,
|
||||
value);
|
||||
|
||||
LLVMTypeRef cbs_type = LLVMTypeOf(cbs);
|
||||
unsigned cblen = LLVMCountStructElementTypes(cbs_type);
|
||||
|
||||
for (unsigned i = 0; i < cblen; i++) {
|
||||
LLVMValueRef cb = LLVMGetOperand(cbs, i);
|
||||
|
||||
char *sname = NULL;
|
||||
char *mname = NULL;
|
||||
|
||||
if (dbginfo_struct_member(dbginfo, cbs_type, i, &sname,
|
||||
&mname)) {
|
||||
(void)0;
|
||||
}
|
||||
|
||||
if (LLVMIsAFunction(cb)) {
|
||||
size_t fn_len;
|
||||
const char *fn_name;
|
||||
|
||||
fn_name = LLVMGetValueName2(cb, &fn_len);
|
||||
|
||||
json_object_object_add(
|
||||
js_cbs, mname,
|
||||
json_object_new_string_len(fn_name,
|
||||
fn_len));
|
||||
}
|
||||
|
||||
free(sname);
|
||||
free(mname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_daemoninfo(struct json_object *js_special,
|
||||
LLVMValueRef daemoninfo)
|
||||
{
|
||||
check_val(LLVMIsAGlobalVariable(daemoninfo), daemoninfo);
|
||||
|
||||
LLVMTypeRef type;
|
||||
LLVMValueRef value;
|
||||
unsigned len;
|
||||
|
||||
type = LLVMGlobalGetValueType(daemoninfo);
|
||||
value = LLVMGetInitializer(daemoninfo);
|
||||
LLVMValueKind kind = LLVMGetValueKind(value);
|
||||
|
||||
check_val(kind == LLVMConstantStructValueKind, value);
|
||||
|
||||
int yang_idx = -1;
|
||||
|
||||
len = LLVMCountStructElementTypes(type);
|
||||
|
||||
LLVMTypeRef fieldtypes[len];
|
||||
LLVMGetSubtypes(type, fieldtypes);
|
||||
|
||||
for (unsigned i = 0; i < len; i++) {
|
||||
LLVMTypeRef t = fieldtypes[i];
|
||||
|
||||
if (LLVMGetTypeKind(t) != LLVMPointerTypeKind)
|
||||
continue;
|
||||
t = LLVMGetElementType(t);
|
||||
if (LLVMGetTypeKind(t) != LLVMPointerTypeKind)
|
||||
continue;
|
||||
t = LLVMGetElementType(t);
|
||||
if (LLVMGetTypeKind(t) != LLVMStructTypeKind)
|
||||
continue;
|
||||
|
||||
const char *name = LLVMGetStructName(t);
|
||||
if (!strcmp(name, "struct.frr_yang_module_info"))
|
||||
yang_idx = i;
|
||||
}
|
||||
|
||||
if (yang_idx == -1)
|
||||
return;
|
||||
|
||||
LLVMValueRef yang_mods = LLVMGetOperand(value, yang_idx);
|
||||
LLVMValueRef yang_size = LLVMGetOperand(value, yang_idx + 1);
|
||||
|
||||
check_val(LLVMIsConstant(yang_size), yang_size);
|
||||
|
||||
unsigned long long ival = LLVMConstIntGetZExtValue(yang_size);
|
||||
|
||||
check_val(LLVMGetValueKind(yang_mods) == LLVMConstantExprValueKind
|
||||
&& LLVMGetConstOpcode(yang_mods) == LLVMGetElementPtr,
|
||||
yang_mods);
|
||||
|
||||
yang_mods = LLVMGetOperand(yang_mods, 0);
|
||||
|
||||
check_val(LLVMIsAGlobalVariable(yang_mods), yang_mods);
|
||||
|
||||
yang_mods = LLVMGetInitializer(yang_mods);
|
||||
|
||||
check_val(LLVMGetValueKind(yang_mods) == LLVMConstantArrayValueKind,
|
||||
yang_mods);
|
||||
|
||||
len = LLVMGetArrayLength(LLVMTypeOf(yang_mods));
|
||||
|
||||
if (len != ival)
|
||||
fprintf(stderr, "length mismatch - %llu vs. %u\n", ival, len);
|
||||
|
||||
for (unsigned i = 0; i < len; i++) {
|
||||
char *dump;
|
||||
|
||||
LLVMValueRef item = LLVMGetOperand(yang_mods, i);
|
||||
LLVMValueKind kind = LLVMGetValueKind(item);
|
||||
|
||||
check_val(kind == LLVMGlobalVariableValueKind
|
||||
|| kind == LLVMConstantExprValueKind,
|
||||
item);
|
||||
|
||||
if (kind == LLVMGlobalVariableValueKind)
|
||||
continue;
|
||||
|
||||
LLVMOpcode opcode = LLVMGetConstOpcode(item);
|
||||
switch (opcode) {
|
||||
case LLVMBitCast:
|
||||
item = LLVMGetOperand(item, 0);
|
||||
handle_yang_module(js_special, item);
|
||||
break;
|
||||
|
||||
default:
|
||||
dump = LLVMPrintValueToString(item);
|
||||
printf("[%u] = [opcode=%u] %s\n", i, opcode, dump);
|
||||
LLVMDisposeMessage(dump);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void process_call(struct json_object *js_calls,
|
||||
struct json_object *js_special,
|
||||
LLVMValueRef instr,
|
||||
|
@ -227,6 +542,9 @@ static void process_call(struct json_object *js_calls,
|
|||
|
||||
LLVMValueRef called = LLVMGetCalledValue(instr);
|
||||
|
||||
if (LLVMIsAInlineAsm(called))
|
||||
return;
|
||||
|
||||
if (LLVMIsAConstantExpr(called)) {
|
||||
LLVMOpcode opcode = LLVMGetConstOpcode(called);
|
||||
|
||||
|
@ -277,6 +595,12 @@ static void process_call(struct json_object *js_calls,
|
|||
snprintf(prefix, sizeof(prefix), "%.*s:%d:%.*s()",
|
||||
(int)file_len, file, line, (int)name_len, name_c);
|
||||
|
||||
if (LLVMIsALoadInst(called)
|
||||
&& LLVMIsAGetElementPtrInst(LLVMGetOperand(called, 0))
|
||||
&& try_struct_fptr(js_call, LLVMGetOperand(called, 0),
|
||||
prefix))
|
||||
goto out_struct_fptr;
|
||||
|
||||
while (LLVMIsALoadInst(last) || LLVMIsAGetElementPtrInst(last))
|
||||
/* skipping over details for GEP here, but meh. */
|
||||
last = LLVMGetOperand(last, 0);
|
||||
|
@ -324,12 +648,11 @@ static void process_call(struct json_object *js_calls,
|
|||
prefix);
|
||||
} else {
|
||||
char *dump = LLVMPrintValueToString(called);
|
||||
printf("\t%s\n", dump);
|
||||
fprintf(stderr, "%s: ??? %s\n", prefix, dump);
|
||||
LLVMDisposeMessage(dump);
|
||||
}
|
||||
return;
|
||||
#ifdef FRR_SPECIFIC
|
||||
} else if (!strcmp(called_name, "install_element")) {
|
||||
} else if (!strcmp(called_name, "_install_element")) {
|
||||
called_type = FN_INSTALL_ELEMENT;
|
||||
|
||||
LLVMValueRef param0 = LLVMGetOperand(instr, 0);
|
||||
|
@ -380,10 +703,7 @@ static void process_call(struct json_object *js_calls,
|
|||
json_object_new_string_len(called_name, called_len));
|
||||
|
||||
LLVMValueRef fparam;
|
||||
if (strstr(called_name, "_read_"))
|
||||
fparam = LLVMGetOperand(instr, 2);
|
||||
else
|
||||
fparam = LLVMGetOperand(instr, 1);
|
||||
fparam = LLVMGetOperand(instr, 2);
|
||||
assert(fparam);
|
||||
|
||||
size_t target_len = 0;
|
||||
|
@ -434,12 +754,21 @@ static void process_call(struct json_object *js_calls,
|
|||
* - zclient->* ?
|
||||
*/
|
||||
#endif /* FRR_SPECIFIC */
|
||||
} else if (!strcmp(called_name, "frr_preinit")) {
|
||||
LLVMValueRef daemoninfo = LLVMGetOperand(instr, 0);
|
||||
|
||||
handle_daemoninfo(js_special, daemoninfo);
|
||||
|
||||
json_object_object_add(
|
||||
js_call, "target",
|
||||
json_object_new_string_len(called_name, called_len));
|
||||
} else {
|
||||
json_object_object_add(
|
||||
js_call, "target",
|
||||
json_object_new_string_len(called_name, called_len));
|
||||
}
|
||||
|
||||
out_struct_fptr:
|
||||
for (unsigned argno = 0; argno < n_args; argno++) {
|
||||
LLVMValueRef param = LLVMGetOperand(instr, argno);
|
||||
size_t target_len;
|
||||
|
@ -597,6 +926,8 @@ int main(int argc, char **argv)
|
|||
// done with the memory buffer now, so dispose of it
|
||||
LLVMDisposeMemoryBuffer(memoryBuffer);
|
||||
|
||||
dbginfo = dbginfo_load(module);
|
||||
|
||||
struct json_object *js_root, *js_funcs, *js_special;
|
||||
|
||||
js_root = json_object_new_object();
|
||||
|
|
112
tools/frr-llvm-debuginfo.cpp
Normal file
112
tools/frr-llvm-debuginfo.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors
|
||||
// of this software dedicate any and all copyright interest in the
|
||||
// software to the public domain. We make this dedication for the benefit
|
||||
// of the public at large and to the detriment of our heirs and
|
||||
// successors. We intend this dedication to be an overt act of
|
||||
// relinquishment in perpetuity of all present and future rights to this
|
||||
// software under copyright law.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
#include <llvm-c/BitReader.h>
|
||||
#include <llvm-c/BitWriter.h>
|
||||
#include <llvm-c/Core.h>
|
||||
#include <llvm-c/DebugInfo.h>
|
||||
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Value.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
#include <llvm/IR/DebugInfo.h>
|
||||
#include <llvm/IR/DebugInfoMetadata.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "frr-llvm-debuginfo.h"
|
||||
|
||||
/* llvm::DebugInfoFinder is unfortunately not exposed in the llvm-c API... */
|
||||
|
||||
struct dbginfo {
|
||||
llvm::DebugInfoFinder finder;
|
||||
std::map<std::string, llvm::DICompositeType *> tab;
|
||||
};
|
||||
|
||||
struct dbginfo *dbginfo_load(LLVMModuleRef _mod)
|
||||
{
|
||||
llvm::Module *mod = llvm::unwrap(_mod);
|
||||
struct dbginfo *info = new dbginfo();
|
||||
|
||||
info->finder.processModule(*mod);
|
||||
|
||||
for (auto ty : info->finder.types()) {
|
||||
if (ty->getMetadataID() != llvm::Metadata::DICompositeTypeKind)
|
||||
continue;
|
||||
|
||||
llvm::DICompositeType *cty = (llvm::DICompositeType *)ty;
|
||||
/* empty forward declarations aka "struct foobar;" */
|
||||
if (cty->getElements().size() == 0)
|
||||
continue;
|
||||
|
||||
info->tab.emplace(std::move(ty->getName().str()), cty);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
bool dbginfo_struct_member(struct dbginfo *info, LLVMTypeRef _typ,
|
||||
unsigned long long idx, char **struct_name,
|
||||
char **member_name)
|
||||
{
|
||||
*struct_name = NULL;
|
||||
*member_name = NULL;
|
||||
|
||||
llvm::Type *typ = llvm::unwrap(_typ);
|
||||
|
||||
if (!typ->isStructTy())
|
||||
return false;
|
||||
|
||||
llvm::StructType *styp = (llvm::StructType *)typ;
|
||||
auto sname = styp->getStructName();
|
||||
|
||||
if (!sname.startswith("struct."))
|
||||
return false;
|
||||
sname = sname.drop_front(7);
|
||||
|
||||
size_t dot = sname.find_last_of(".");
|
||||
if (dot != sname.npos)
|
||||
sname = sname.take_front(dot);
|
||||
|
||||
auto item = info->tab.find(sname.str());
|
||||
if (item == info->tab.end())
|
||||
return false;
|
||||
|
||||
auto elements = item->second->getElements();
|
||||
if (idx >= elements.size())
|
||||
return false;
|
||||
|
||||
auto elem = elements[idx];
|
||||
|
||||
if (elem->getMetadataID() != llvm::Metadata::DIDerivedTypeKind)
|
||||
return false;
|
||||
|
||||
llvm::DIDerivedType *dtyp = (llvm::DIDerivedType *)elem;
|
||||
|
||||
*struct_name = strdup(sname.str().c_str());
|
||||
*member_name = strdup(dtyp->getName().str().c_str());
|
||||
return true;
|
||||
}
|
47
tools/frr-llvm-debuginfo.h
Normal file
47
tools/frr-llvm-debuginfo.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors
|
||||
// of this software dedicate any and all copyright interest in the
|
||||
// software to the public domain. We make this dedication for the benefit
|
||||
// of the public at large and to the detriment of our heirs and
|
||||
// successors. We intend this dedication to be an overt act of
|
||||
// relinquishment in perpetuity of all present and future rights to this
|
||||
// software under copyright law.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
#ifndef _FRR_LLVM_DEBUGINFO_H
|
||||
#define _FRR_LLVM_DEBUGINFO_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <llvm-c/Core.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct dbginfo;
|
||||
|
||||
extern struct dbginfo *dbginfo_load(LLVMModuleRef mod);
|
||||
extern bool dbginfo_struct_member(struct dbginfo *di, LLVMTypeRef typ,
|
||||
unsigned long long idx, char **struct_name,
|
||||
char **member_name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FRR_LLVM_DEBUGINFO_H */
|
|
@ -40,9 +40,15 @@ tools_ssd_CPPFLAGS =
|
|||
llvm_version = $(shell echo __clang_major__ | $(CC) -xc -P -E -)
|
||||
tools_frr_llvm_cg_CPPFLAGS = $(CPPFLAGS_BASE)
|
||||
tools_frr_llvm_cg_CFLAGS = $(AM_CFLAGS) `llvm-config-$(llvm_version) --cflags`
|
||||
tools_frr_llvm_cg_CXXFLAGS = $(AM_CXXFLAGS) -O0 -ggdb3 `llvm-config-$(llvm_version) --cxxflags`
|
||||
tools_frr_llvm_cg_LDFLAGS = `llvm-config-$(llvm_version) --ldflags --libs`
|
||||
tools_frr_llvm_cg_SOURCES = \
|
||||
tools/frr-llvm-cg.c \
|
||||
tools/frr-llvm-debuginfo.cpp \
|
||||
# end
|
||||
|
||||
noinst_HEADERS += \
|
||||
tools/frr-llvm-debuginfo.h \
|
||||
# end
|
||||
|
||||
EXTRA_DIST += \
|
||||
|
|
Loading…
Reference in a new issue