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
|
/libtool.orig
|
||||||
/changelog-auto
|
/changelog-auto
|
||||||
/test-driver
|
/test-driver
|
||||||
|
/test-suite.log
|
||||||
|
|
||||||
/Makefile
|
/Makefile
|
||||||
/Makefile.in
|
/Makefile.in
|
||||||
|
@ -57,6 +58,7 @@
|
||||||
*.pb.cc
|
*.pb.cc
|
||||||
*_clippy.c
|
*_clippy.c
|
||||||
*.bc
|
*.bc
|
||||||
|
*.ll
|
||||||
*.cg.json
|
*.cg.json
|
||||||
*.cg.dot
|
*.cg.dot
|
||||||
*.cg.svg
|
*.cg.svg
|
||||||
|
|
|
@ -315,10 +315,12 @@ struct prefix_sg {
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
#define prefixtype(uname, typename, fieldname) \
|
#define prefixtype(uname, typename, fieldname) \
|
||||||
typename *fieldname;
|
typename *fieldname;
|
||||||
|
#define TRANSPARENT_UNION __attribute__((transparent_union))
|
||||||
#else
|
#else
|
||||||
#define prefixtype(uname, typename, fieldname) \
|
#define prefixtype(uname, typename, fieldname) \
|
||||||
typename *fieldname; \
|
typename *fieldname; \
|
||||||
uname(typename *x) { this->fieldname = x; }
|
uname(typename *x) { this->fieldname = x; }
|
||||||
|
#define TRANSPARENT_UNION
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
union prefixptr {
|
union prefixptr {
|
||||||
|
@ -328,7 +330,7 @@ union prefixptr {
|
||||||
prefixtype(prefixptr, struct prefix_evpn, evp)
|
prefixtype(prefixptr, struct prefix_evpn, evp)
|
||||||
prefixtype(prefixptr, struct prefix_fs, fs)
|
prefixtype(prefixptr, struct prefix_fs, fs)
|
||||||
prefixtype(prefixptr, struct prefix_rd, rd)
|
prefixtype(prefixptr, struct prefix_rd, rd)
|
||||||
} __attribute__((transparent_union));
|
} TRANSPARENT_UNION;
|
||||||
|
|
||||||
union prefixconstptr {
|
union prefixconstptr {
|
||||||
prefixtype(prefixconstptr, const struct prefix, p)
|
prefixtype(prefixconstptr, const struct prefix, p)
|
||||||
|
@ -337,7 +339,10 @@ union prefixconstptr {
|
||||||
prefixtype(prefixconstptr, const struct prefix_evpn, evp)
|
prefixtype(prefixconstptr, const struct prefix_evpn, evp)
|
||||||
prefixtype(prefixconstptr, const struct prefix_fs, fs)
|
prefixtype(prefixconstptr, const struct prefix_fs, fs)
|
||||||
prefixtype(prefixconstptr, const struct prefix_rd, rd)
|
prefixtype(prefixconstptr, const struct prefix_rd, rd)
|
||||||
} __attribute__((transparent_union));
|
} TRANSPARENT_UNION;
|
||||||
|
|
||||||
|
#undef prefixtype
|
||||||
|
#undef TRANSPARENT_UNION
|
||||||
|
|
||||||
#ifndef INET_ADDRSTRLEN
|
#ifndef INET_ADDRSTRLEN
|
||||||
#define INET_ADDRSTRLEN 16
|
#define INET_ADDRSTRLEN 16
|
||||||
|
|
1
tools/.gitignore
vendored
1
tools/.gitignore
vendored
|
@ -8,3 +8,4 @@
|
||||||
/frrcommon.sh
|
/frrcommon.sh
|
||||||
/frr.service
|
/frr.service
|
||||||
/frr@.service
|
/frr@.service
|
||||||
|
/frr-llvm-cg
|
||||||
|
|
|
@ -50,11 +50,15 @@
|
||||||
|
|
||||||
#include <json-c/json.h>
|
#include <json-c/json.h>
|
||||||
|
|
||||||
|
#include "frr-llvm-debuginfo.h"
|
||||||
|
|
||||||
/* if you want to use this without the special FRRouting defines,
|
/* if you want to use this without the special FRRouting defines,
|
||||||
* remove the following #define
|
* remove the following #define
|
||||||
*/
|
*/
|
||||||
#define FRR_SPECIFIC
|
#define FRR_SPECIFIC
|
||||||
|
|
||||||
|
static struct dbginfo *dbginfo;
|
||||||
|
|
||||||
static void dbgloc_add(struct json_object *jsobj, LLVMValueRef obj)
|
static void dbgloc_add(struct json_object *jsobj, LLVMValueRef obj)
|
||||||
{
|
{
|
||||||
unsigned file_len = 0;
|
unsigned file_len = 0;
|
||||||
|
@ -85,6 +89,70 @@ static struct json_object *js_get_or_make(struct json_object *parent,
|
||||||
return ret;
|
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_vars = false;
|
||||||
static bool details_fptr_consts = true;
|
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);
|
prefix, hdr_written);
|
||||||
return;
|
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:
|
default:
|
||||||
/* to help the user / development */
|
/* to help the user / development */
|
||||||
if (!*hdr_written) {
|
if (!*hdr_written) {
|
||||||
|
@ -197,7 +293,7 @@ static void walk_const_fptrs(struct json_object *js_call, LLVMValueRef value,
|
||||||
#ifdef FRR_SPECIFIC
|
#ifdef FRR_SPECIFIC
|
||||||
static bool is_thread_sched(const char *name, size_t len)
|
static bool is_thread_sched(const char *name, size_t len)
|
||||||
{
|
{
|
||||||
#define thread_prefix "funcname_"
|
#define thread_prefix "_"
|
||||||
static const char *const names[] = {
|
static const char *const names[] = {
|
||||||
thread_prefix "thread_add_read_write",
|
thread_prefix "thread_add_read_write",
|
||||||
thread_prefix "thread_add_timer",
|
thread_prefix "thread_add_timer",
|
||||||
|
@ -218,6 +314,225 @@ static bool is_thread_sched(const char *name, size_t len)
|
||||||
}
|
}
|
||||||
#endif
|
#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,
|
static void process_call(struct json_object *js_calls,
|
||||||
struct json_object *js_special,
|
struct json_object *js_special,
|
||||||
LLVMValueRef instr,
|
LLVMValueRef instr,
|
||||||
|
@ -227,6 +542,9 @@ static void process_call(struct json_object *js_calls,
|
||||||
|
|
||||||
LLVMValueRef called = LLVMGetCalledValue(instr);
|
LLVMValueRef called = LLVMGetCalledValue(instr);
|
||||||
|
|
||||||
|
if (LLVMIsAInlineAsm(called))
|
||||||
|
return;
|
||||||
|
|
||||||
if (LLVMIsAConstantExpr(called)) {
|
if (LLVMIsAConstantExpr(called)) {
|
||||||
LLVMOpcode opcode = LLVMGetConstOpcode(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()",
|
snprintf(prefix, sizeof(prefix), "%.*s:%d:%.*s()",
|
||||||
(int)file_len, file, line, (int)name_len, name_c);
|
(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))
|
while (LLVMIsALoadInst(last) || LLVMIsAGetElementPtrInst(last))
|
||||||
/* skipping over details for GEP here, but meh. */
|
/* skipping over details for GEP here, but meh. */
|
||||||
last = LLVMGetOperand(last, 0);
|
last = LLVMGetOperand(last, 0);
|
||||||
|
@ -324,12 +648,11 @@ static void process_call(struct json_object *js_calls,
|
||||||
prefix);
|
prefix);
|
||||||
} else {
|
} else {
|
||||||
char *dump = LLVMPrintValueToString(called);
|
char *dump = LLVMPrintValueToString(called);
|
||||||
printf("\t%s\n", dump);
|
fprintf(stderr, "%s: ??? %s\n", prefix, dump);
|
||||||
LLVMDisposeMessage(dump);
|
LLVMDisposeMessage(dump);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
#ifdef FRR_SPECIFIC
|
#ifdef FRR_SPECIFIC
|
||||||
} else if (!strcmp(called_name, "install_element")) {
|
} else if (!strcmp(called_name, "_install_element")) {
|
||||||
called_type = FN_INSTALL_ELEMENT;
|
called_type = FN_INSTALL_ELEMENT;
|
||||||
|
|
||||||
LLVMValueRef param0 = LLVMGetOperand(instr, 0);
|
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));
|
json_object_new_string_len(called_name, called_len));
|
||||||
|
|
||||||
LLVMValueRef fparam;
|
LLVMValueRef fparam;
|
||||||
if (strstr(called_name, "_read_"))
|
fparam = LLVMGetOperand(instr, 2);
|
||||||
fparam = LLVMGetOperand(instr, 2);
|
|
||||||
else
|
|
||||||
fparam = LLVMGetOperand(instr, 1);
|
|
||||||
assert(fparam);
|
assert(fparam);
|
||||||
|
|
||||||
size_t target_len = 0;
|
size_t target_len = 0;
|
||||||
|
@ -434,12 +754,21 @@ static void process_call(struct json_object *js_calls,
|
||||||
* - zclient->* ?
|
* - zclient->* ?
|
||||||
*/
|
*/
|
||||||
#endif /* FRR_SPECIFIC */
|
#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 {
|
} else {
|
||||||
json_object_object_add(
|
json_object_object_add(
|
||||||
js_call, "target",
|
js_call, "target",
|
||||||
json_object_new_string_len(called_name, called_len));
|
json_object_new_string_len(called_name, called_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_struct_fptr:
|
||||||
for (unsigned argno = 0; argno < n_args; argno++) {
|
for (unsigned argno = 0; argno < n_args; argno++) {
|
||||||
LLVMValueRef param = LLVMGetOperand(instr, argno);
|
LLVMValueRef param = LLVMGetOperand(instr, argno);
|
||||||
size_t target_len;
|
size_t target_len;
|
||||||
|
@ -597,6 +926,8 @@ int main(int argc, char **argv)
|
||||||
// done with the memory buffer now, so dispose of it
|
// done with the memory buffer now, so dispose of it
|
||||||
LLVMDisposeMemoryBuffer(memoryBuffer);
|
LLVMDisposeMemoryBuffer(memoryBuffer);
|
||||||
|
|
||||||
|
dbginfo = dbginfo_load(module);
|
||||||
|
|
||||||
struct json_object *js_root, *js_funcs, *js_special;
|
struct json_object *js_root, *js_funcs, *js_special;
|
||||||
|
|
||||||
js_root = json_object_new_object();
|
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 -)
|
llvm_version = $(shell echo __clang_major__ | $(CC) -xc -P -E -)
|
||||||
tools_frr_llvm_cg_CPPFLAGS = $(CPPFLAGS_BASE)
|
tools_frr_llvm_cg_CPPFLAGS = $(CPPFLAGS_BASE)
|
||||||
tools_frr_llvm_cg_CFLAGS = $(AM_CFLAGS) `llvm-config-$(llvm_version) --cflags`
|
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_LDFLAGS = `llvm-config-$(llvm_version) --ldflags --libs`
|
||||||
tools_frr_llvm_cg_SOURCES = \
|
tools_frr_llvm_cg_SOURCES = \
|
||||||
tools/frr-llvm-cg.c \
|
tools/frr-llvm-cg.c \
|
||||||
|
tools/frr-llvm-debuginfo.cpp \
|
||||||
|
# end
|
||||||
|
|
||||||
|
noinst_HEADERS += \
|
||||||
|
tools/frr-llvm-debuginfo.h \
|
||||||
# end
|
# end
|
||||||
|
|
||||||
EXTRA_DIST += \
|
EXTRA_DIST += \
|
||||||
|
|
Loading…
Reference in a new issue