📄 bfdreflect.cpp
字号:
#include <alloca.h>
#include <assert.h>
#include "bfdreflect.h"
RTTIBfdRepository RTTIBfdRepository::theRepository;
void RTTIStackFrameMethodType::calculateFrameSize()
{
int frameSize = 0;
for (int i = 0; i < nParams; i++) {
switch (paramTypes[i]->getTag()) {
case RTTI_BOOL:
case RTTI_CHAR:
case RTTI_UCHAR:
case RTTI_SCHAR:
case RTTI_SHORT:
case RTTI_USHORT:
case RTTI_INT:
case RTTI_UINT:
frameSize += sizeof(int);
break;
case RTTI_LONG:
case RTTI_ULONG:
frameSize += sizeof(long);
case RTTI_FLOAT:
case RTTI_DOUBLE:
frameSize += sizeof(double);
break;
case RTTI_ARRAY:
case RTTI_PTR:
frameSize += sizeof(void*);
break;
}
}
if (!isStatic) {
frameSize += sizeof(void*);
}
this->frameSize = frameSize;
}
void RTTIStackFrameMethodType::invoke(void* result, void* obj, void* params[])
{
assert (methodAddress != NULL);
char* fp;
char* frame = NULL;
if (frameSize != 0) {
frame = (char*)alloca(frameSize);
}
fp = frame;
if (!isStatic) {
*(void**)fp = obj;
fp += sizeof(void*);
}
for (int i = 0, n = nParams; i < n; i++) {
switch (paramTypes[i]->getTag()) {
case RTTI_CHAR:
*(int*)fp = *(char*)params[i];
fp += sizeof(int);
break;
case RTTI_SCHAR:
*(int*)fp = *(signed char*)params[i];
fp += sizeof(int);
break;
case RTTI_UCHAR:
*(int*)fp = *(unsigned char*)params[i];
fp += sizeof(int);
break;
case RTTI_SHORT:
*(int*)fp = *(short*)params[i];
fp += sizeof(int);
break;
case RTTI_USHORT:
*(int*)fp = *(unsigned short*)params[i];
fp += sizeof(int);
break;
case RTTI_INT:
case RTTI_UINT:
*(int*)fp = *(int*)params[i];
fp += sizeof(int);
break;
case RTTI_LONG:
case RTTI_ULONG:
*(long*)fp = *(long*)params[i];
fp += sizeof(long);
break;
case RTTI_FLOAT:
*(double*)fp = *(float*)params[i];
fp += sizeof(double);
break;
case RTTI_DOUBLE:
*(double*)fp = *(double*)params[i];
fp += sizeof(double);
break;
case RTTI_PTR:
case RTTI_ARRAY:
*(void**)fp = *(void**)params[i];
fp += sizeof(void*);
break;
}
}
switch (returnType->getTag()) {
case RTTI_VOID:
(*(void(*)())methodAddress)();
break;
case RTTI_CHAR:
case RTTI_SCHAR:
case RTTI_UCHAR:
*(char*)result = (*(char(*)())methodAddress)();
break;
case RTTI_SHORT:
case RTTI_USHORT:
*(short*)result = (*(short(*)())methodAddress)();
break;
case RTTI_INT:
case RTTI_UINT:
*(int*)result = (*(int(*)())methodAddress)();
break;
case RTTI_LONG:
case RTTI_ULONG:
*(long*)result = (*(long(*)())methodAddress)();
break;
case RTTI_FLOAT:
*(float*)result = (*(float(*)())methodAddress)();
break;
case RTTI_DOUBLE:
*(double*)result = (*(double(*)())methodAddress)();
break;
case RTTI_PTR:
case RTTI_ARRAY:
*(void**)result = (*(void*(*)())methodAddress)();
break;
default:
break;
}
}
int RTTIBfdRepository::getVisibility(enum debug_visibility visibility)
{
switch (visibility) {
case DEBUG_VISIBILITY_PUBLIC:
return RTTI_FLD_PUBLIC;
break;
case DEBUG_VISIBILITY_PROTECTED:
return RTTI_FLD_PROTECTED;
break;
case DEBUG_VISIBILITY_PRIVATE:
return RTTI_FLD_PRIVATE;
break;
}
return 0;
}
int RTTIBfdRepository::getTypeQualifiers(debug_type* type)
{
switch (type->kind) {
case DEBUG_KIND_VOLATILE:
return RTTI_FLD_VOLATILE | getTypeQualifiers(type->u.kvolatile);
case DEBUG_KIND_CONST:
return RTTI_FLD_CONST | getTypeQualifiers(type->u.kconst);
default:
return 0;
}
}
RTTIType* RTTIBfdRepository::getType(debug_type* type)
{
RTTIClassDescriptor* cls;
switch (type->kind) {
case DEBUG_KIND_VOID:
return &RTTIType::voidType;
case DEBUG_KIND_ENUM:
case DEBUG_KIND_INT:
if (type->u.kint) {
if (type->size == sizeof(char)) {
return &RTTIType::charType;
} else if (type->size == sizeof(short)) {
return &RTTIType::shortType;
} else if (type->size == sizeof(int)) {
return &RTTIType::intType;
} else if (type->size == sizeof(long)) {
return &RTTIType::longType;
} else {
return &RTTIType::unknownType;
}
} else {
if (type->size == sizeof(char)) {
return &RTTIType::ucharType;
} else if (type->size == sizeof(short)) {
return &RTTIType::ushortType;
} else if (type->size == sizeof(int)) {
return &RTTIType::uintType;
} else if (type->size == sizeof(long)) {
return &RTTIType::ulongType;
} else {
return &RTTIType::unknownType;
}
}
/* Floating point. */
case DEBUG_KIND_FLOAT:
return type->size == sizeof(float) ? &RTTIType::floatType : &RTTIType::doubleType;
/* Boolean. */
case DEBUG_KIND_BOOL:
return &RTTIType::boolType;
case DEBUG_KIND_INDIRECT:
if (*type->u.kindirect->slot != NULL) {
return getType(*type->u.kindirect->slot);
}
cls = findClass(type->u.kindirect->tag);
if (cls == NULL) {
printf("Failed to find tag '%s'\n", type->u.kindirect->tag);
return &RTTIType::unknownType;
}
return cls;
case DEBUG_KIND_NAMED:
case DEBUG_KIND_TAGGED:
if (type->u.knamed->type->kind == DEBUG_KIND_CLASS ||
type->u.knamed->type->kind == DEBUG_KIND_STRUCT)
{
cls = findClass(type->u.knamed->name->name);
if (cls == NULL) {
printf("Failed to find class '%s'\n", type->u.knamed->name->name);
return &RTTIType::unknownType;
}
return cls;
} else {
return getType(type->u.knamed->type);
}
case DEBUG_KIND_FUNCTION:
return &RTTIType::voidType;
case DEBUG_KIND_POINTER:
return new RTTIPtrType(getType(type->u.kpointer));
case DEBUG_KIND_REFERENCE:
return new RTTIPtrType(getType(type->u.kreference));
case DEBUG_KIND_ARRAY:
return new RTTIArrayType(getType(type->u.karray->element_type), type->u.karray->upper - type->u.karray->lower + 1);
case DEBUG_KIND_VOLATILE:
return getType(type->u.kvolatile);
case DEBUG_KIND_CONST:
return getType(type->u.kconst);
default:
// printf("Unknown type %d\n", type->kind);
return &RTTIType::unknownType;
}
}
void RTTIBfdRepository::loadClass(debug_type* type)
{
debug_type* real = debug_get_real_type(handle, type, NULL);
if (real->u.kclass != NULL) {
RTTIClassDescriptor* cls = new RTTIClassDescriptor(type->u.knamed->name->name,
type->size,
0);
addClass(cls);
}
}
void RTTIBfdRepository::readClass(debug_type* type)
{
debug_type* real = debug_get_real_type(handle, type, NULL);
if (real->u.kclass != NULL) {
int i;
char const* className = type->u.knamed->name->name;
RTTIClassDescriptor* cls = findClass(className);
if (cls == NULL || cls->initialized) {
return;
}
RTTIFieldDescriptor **fdp = &cls->fieldList;
if (real->u.kclass->baseclasses != NULL) {
for (i = 0; real->u.kclass->baseclasses[i] != NULL; i++) {
debug_baseclass* b = real->u.kclass->baseclasses[i];
char const* baseClassName = b->type->kind == DEBUG_KIND_NAMED ? b->type->u.knamed->name->name
: b->type->u.kindirect->tag;
RTTIClassDescriptor* baseClass = findClass(baseClassName);
int flags = getVisibility(b->visibility);
if (b->is_virtual) {
flags |= RTTI_FLD_VIRTUAL;
}
RTTIFieldDescriptor* fd = new RTTIFieldDescriptor(baseClassName, b->bitpos/8,
b->type->size, flags,
new RTTIDerivedType(baseClass));
*fdp = fd;
fdp = &fd->next;
}
}
if (real->u.kclass->fields != NULL) {
for (i = 0; real->u.kclass->fields[i] != NULL; i++) {
debug_field* f = real->u.kclass->fields[i];
int flags = getTypeQualifiers(f->type) | getVisibility(f->visibility);
if (f->static_member) {
flags |= RTTI_FLD_STATIC;
}
RTTIFieldDescriptor* fd = new RTTIFieldDescriptor(f->name, f->u.f.bitpos/8, f->u.f.bitsize/8, flags, getType(f->type));
*fdp = fd;
fdp = &fd->next;
}
}
*fdp = NULL;
RTTIMethodDescriptor **mdp = &cls->methodList;
if (real->u.kclass->methods != NULL) {
for (i = 0; real->u.kclass->methods[i] != NULL; i++) {
debug_method* m = real->u.kclass->methods[i];
unsigned int j, k, n;
int commonFlags = (strcmp(constructorName, m->name) == 0 || strcmp(className, m->name) == 0)
? RTTI_MTH_CONSTRUCTOR : 0;
for (j = 0; m->variants[j] != NULL; j++) {
debug_method_variant* v = m->variants[j];
int flags = commonFlags | getVisibility(v->visibility);
if (v->voffset == VOFFSET_STATIC_METHOD) {
flags |= RTTI_MTH_STATIC;
}
if (v->constp) {
flags |= RTTI_MTH_CONST;
}
RTTIStackFrameMethodType* type = new RTTIStackFrameMethodType();
type->returnType = getType(v->type->u.kmethod->return_type);
type->methodClass = cls;
type->methodAddress = (void*)v->address;
RTTIMethodDescriptor* md = new RTTIMethodDescriptor(m->name, flags, type);
if (v->type->u.kmethod->arg_types != NULL) {
for (k = 0; v->type->u.kmethod->arg_types[k] != NULL; k++);
int n = 0;
#if defined(__GNUC__) && __GNUC_MAJOR__ >= 3
if (k > 0 && (flags & (RTTI_MTH_CONSTRUCTOR|RTTI_MTH_STATIC)) == 0) {
k -= 1;
n = 1;
}
#endif
type->nParams = k;
type->paramTypes = new RTTIType*[k];
k = 0;
while (v->type->u.kmethod->arg_types[n] != NULL) {
type->paramTypes[k++] = getType(v->type->u.kmethod->arg_types[n++]);
}
type->calculateFrameSize();
} else {
type->nParams = 0;
type->paramTypes = NULL;
type->frameSize = 0;
}
if (type->nParams == 0 && (flags & RTTI_MTH_CONSTRUCTOR) != 0) {
cls->defaultConstructor = (RTTIClassDescriptor::RTTIDefaultConstructor)type->methodAddress;
}
*mdp = md;
mdp = &md->next;
}
}
}
*mdp = NULL;
cls->buildClassDescriptor();
}
}
bool RTTIBfdRepository::readBFD(bfd* abfd)
{
asymbol **syms = NULL;
long storage;
if (!(bfd_get_file_flags (abfd) & HAS_SYMS))
{
return false;
}
storage = bfd_get_symtab_upper_bound (abfd);
if (storage < 0) {
bfd_fatal (bfd_get_filename (abfd));
}
if (storage) {
syms = (asymbol **) xmalloc (storage);
}
int symcount = bfd_canonicalize_symtab (abfd, syms);
if (symcount < 0) {
bfd_fatal (bfd_get_filename (abfd));
}
handle = read_debugging_info (abfd, syms, symcount);
if (handle == NULL) {
return false;
}
debug_type** classes = debug_get_all_classes(handle);
if (classes != NULL) {
int i;
for (i = 0; classes[i] != NULL; i++) {
loadClass(classes[i]);
}
for (i = 0; classes[i] != NULL; i++) {
readClass(classes[i]);
}
}
}
bool RTTIBfdRepository::loadBFD(bfd *abfd)
{
char **matching;
if (bfd_check_format_matches (abfd, bfd_object, &matching)) {
return readBFD(abfd);
}
if (bfd_get_error() == bfd_error_file_ambiguously_recognized
|| bfd_get_error() != bfd_error_file_not_recognized)
{
return false;
}
if (bfd_check_format_matches (abfd, bfd_core, &matching)) {
return readBFD(abfd);
}
return false;
}
bool RTTIBfdRepository::load(char const* filePath)
{
bfd *file, *arfile = (bfd *) NULL;
file = bfd_openr (filePath, NULL);
if (file == NULL) {
return false;
}
if (bfd_check_format (file, bfd_archive) == true) {
bfd *last_arfile = NULL;
printf ("In archive %s:\n", bfd_get_filename (file));
for (;;) {
bfd_set_error (bfd_error_no_error);
arfile = bfd_openr_next_archived_file (file, arfile);
if (arfile == NULL) {
if (bfd_get_error () != bfd_error_no_more_archived_files) {
return false;
}
}
loadBFD(arfile);
if (last_arfile != NULL) {
bfd_close (last_arfile);
}
last_arfile = arfile;
}
if (last_arfile != NULL) {
bfd_close (last_arfile);
}
} else {
loadBFD (file);
}
bfd_close (file);
}
RTTIBfdRepository::~RTTIBfdRepository()
{
for (RTTIClassDescriptor* cls = classes; cls != NULL; cls = cls->next) {
delete cls;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -