Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for reading methods via "members" array #72

Closed
wants to merge 4 commits into from

Conversation

jgkamat
Copy link
Contributor

@jgkamat jgkamat commented Oct 1, 2020

This is the first step towards real "method" support (ie: reading methods like Class::methodname). It also adds support for instance.method right now, and adds the methods to the members array of object types.

Here are the biggest red flags (that I would like input on):

  • Right now the python side is completely unaware that parameters can be objects - this works because objects can be automagically evaluated to types. Is this fine for now, or would you like that to be implemented here as well.
  • Anywhere outside the core - parameters are converted to types for compatibility. Is there anywhere a dual pathway makes sense.
  • I am using the lazy_type and lazy_object variable names to signify the parameter must be a type/object at that point. I could split things a little more to remove this distinction if you wish.
  • I still need to work on adding tests.

If you have high-level suggestions for the architecture, I'm also happy to hear those as well.

Copy link
Owner

@osandov osandov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The architecture all looks good here. There are a couple of bugs I spotted, but my comments are mostly around naming and commit organization.

@@ -1026,6 +1026,7 @@ struct drgn_type_from_dwarf_thunk {
struct drgn_type_thunk thunk;
Dwarf_Die die;
bool can_be_incomplete_array;
uint64_t bias;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, and hopefully it's not too much trouble to change this, but I think of the die, bias pair as one entity, so I'd prefer if bias was immediately after die here and in parameter lists where they're passed together.

libdrgn/debug_info.c Outdated Show resolved Hide resolved
libdrgn/Makefile.am Outdated Show resolved Hide resolved
libdrgn/python/drgnpy.h Outdated Show resolved Hide resolved
libdrgn/python/drgnpy.h Outdated Show resolved Hide resolved
libdrgn/object.h Outdated
struct drgn_object *object)
{
lazy_object->object = object;
if (object)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a good reason for this to be NULL. I'm assuming you did this because drgn_lazy_type_init_evaluated() says it can take a NULL type, but I think that documentation is wrong ;) it doesn't make sense for that to take NULL either as far as I can tell.

Also, again because objects are immutable, this needs to allocate a new object and copy the passed object (which of course means that `drgn_lazy_parameter_get_object() should manually reinitialize the lazy parameter rather than calling this). I think this will only end up being needed for the Python bindings, in case someone constructs a member with an object.

libdrgn/object.h Outdated Show resolved Hide resolved
Comment on lines 1591 to 1595
err = drgn_compound_type_builder_add_member(builder, member, name,
0, bit_field_size);
if (err)
goto err;
return NULL;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you refactor this so you only need to call drgn_compound_type_builder_add_member() in one place?

@@ -319,6 +319,8 @@ struct drgn_error *drgn_dwarf_index_get_die(struct drgn_dwarf_index_die *die,
Dwarf_Die *die_ret,
uint64_t *bias_ret);

bool find_definition(struct drgn_dwarf_index *dindex, uintptr_t die_addr,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is being made public, it should be renamed drgn_dwarf_index_find_definition() and given a comment.

libdrgn/type.c Outdated
return err;
struct drgn_error *err = NULL;
if (!parameter.is_object) {
err = drgn_lazy_type_check_prog(&parameter, builder->prog);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to check this in the is_object case, too, right?

@jgkamat jgkamat force-pushed the jay/methods branch 3 times, most recently from 397751f to 5e6b5fd Compare October 10, 2020 00:06
if (!dwarf_flag(die, DW_AT_declaration, &decl) && decl) {
Dwfl_Module *module;
Dwarf_Off offset;
if (drgn_dwarf_index_find_definition(&dbinfo->dindex, (uintptr_t)die->addr, &module, &offset)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self - if we aren't able to find a declaration here, the object returned is pretty odd and can probably cause a crash if mishandled. Not sure if we should worry about that at the moment - but I have been able to generate class functions with no declarations (usually if the function was not used or defined)

Copy link
Owner

@osandov osandov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't look at the final commit in much detail yet, but wanted to send you the comments on the lazy object handling.

drgn_type_thunk_free(lazy_parameter->thunk);
}

inline struct drgn_error *
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd just drop the inline now that this has been moved to a .c file.

}
return NULL;
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stray blank line.

* Validate a @ref drgn_program matches the one in a @ref drgn_lazy_parameter.
*
* @param[in] lazy_parameter Lazy parameter to validate.
* @param[in] prog The program to compare against..
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra "."

Comment on lines +11 to +12
else
free(lazy_parameter->object);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also need to call drgn_object_deinit() first.

Comment on lines +13 to +14
} else
if (!drgn_lazy_parameter_is_evaluated(lazy_parameter))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Squash these to else if.

drgn_lazy_parameter_init_object(lazy_parameter, &obj);
thunk.free_fn(thunk_ptr);
}
drgn_object_init(ret, drgn_object_program(lazy_parameter->object));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convention in libdrgn is to assume that a passed object is already initialized. Rather than calling drgn_object_init() here, the caller should do it.

}
drgn_object_init(ret, drgn_object_program(lazy_parameter->object));
drgn_object_copy(ret, lazy_parameter->object);
*ret = *lazy_parameter->object;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drgn_object_copy() already effectively did this, so this shouldn't be necessary and isn't safe since the object may have an allocated buffer.

struct drgn_error *err = thunk.evaluate_fn(thunk_ptr, &obj);
if (err)
return err;
drgn_lazy_parameter_init_object(lazy_parameter, &obj);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using drgn_lazy_parameter_init_object() means that you're creating a temporary object only to copy it and then discard it. I'd just malloc() the new object directly and reinitialize the lazy parameter here.

if (!new_obj)
return &drgn_enomem;
drgn_object_init(new_obj, drgn_object_program(object));
drgn_object_copy(new_obj, object);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can fail, you need to handle errors.

struct drgn_object_thunk thunk;
Dwarf_Die die;
uint64_t bias;
const char* name;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const char *name

@osandov osandov mentioned this pull request Oct 13, 2021
@osandov
Copy link
Owner

osandov commented Oct 21, 2021

This will be superseded by #123, so I'm closing this in favor of exposing methods that way instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants