-
Notifications
You must be signed in to change notification settings - Fork 164
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
Provide source code info for Symbol #180
base: main
Are you sure you want to change the base?
Conversation
02ab1f2
to
0d2772a
Compare
Hi @PaulZ-98, I just wanted to provide some feedback on this. I'm not a maintainer so Omar's opinion will matter more here, but he may not be able to get back to you for a week or two. First, this is a great idea, thanks for contributing it! Second, regarding your question:
These are generated from the Third, I have a few notes regarding the approach.
I'll also put a few code review notes in the PR itself, which should help regardless of whether Omar agrees with me on the approach. Again, thanks for this and I hope to see it merged :) |
libdrgn/python/symbol.c
Outdated
|
||
if (!PyArg_ParseTupleAndKeywords(args, | ||
kwargs, | ||
"iii", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the Python docs you can use "k" to mean "unsigned long". That way you can support the full width of unsigned long and don't need the cast.
Further, you can use p
to mean bool (see here), so that your bool usage above makes sense and matches the type stubs you created.
"iii", | |
"kpp", |
libdrgn/python/symbol.c
Outdated
return NULL; | ||
|
||
(void) drgn_symbol_source(((Symbol *)self)->sym, p, | ||
(unsigned long)offset, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you've changed to unsigned long, then avoid the cast.
(unsigned long)offset, | |
offset, |
libdrgn/python/symbol.c
Outdated
struct drgn_program *p = &prgm->prog; | ||
int ln_num = 0; | ||
int ln_col = 0; | ||
int offset, line_number, line_column; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Offset should be unsigned long
, and it would be cleaner to use bool for line_number and line_column - since you have ln_num and ln_col above, and it's not clear what their purpose will be.
int offset, line_number, line_column; | |
bool line_number, line_column; | |
unsigned long offset; |
libdrgn/symbol.c
Outdated
@@ -40,6 +45,39 @@ void drgn_symbol_from_elf(const char *name, uint64_t address, | |||
ret->kind = DRGN_SYMBOL_KIND_UNKNOWN; | |||
} | |||
|
|||
LIBDRGN_PUBLIC void drgn_symbol_source(struct drgn_symbol *sym, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This API has no way of showing whether it succeeded or failed. Return struct drgn_error *
and return NULL on success.
LIBDRGN_PUBLIC void drgn_symbol_source(struct drgn_symbol *sym, | |
LIBDRGN_PUBLIC struct drgn_error * | |
drgn_symbol_source(struct drgn_symbol *sym, |
libdrgn/symbol.c
Outdated
*line_col_ret = linecol; | ||
} | ||
|
||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return; | |
return NULL; |
libdrgn/symbol.c
Outdated
int *line_col_ret) | ||
{ | ||
if (sym->kind != DRGN_SYMBOL_KIND_FUNC) | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs an error return, otherwise caller won't know if src_file_ret
is a valid string.
libdrgn/symbol.c
Outdated
if (dim == NULL) | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same, needs error return.
libdrgn/symbol.c
Outdated
if (line == NULL) | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same.
libdrgn/python/symbol.c
Outdated
char source[256]; | ||
char formatted[296]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where do the magic numbers come from? Comments would be nice here, though if you end up ditching the string formatting, then it will be irrelevant.
Thanks for reviewing @brenns10 I will go through your comments and start making changes. |
0d2772a
to
868ca70
Compare
For function symbols, provide the source code file, line number, and column. Signed-off-by: Paul Zuchowski <[email protected]>
868ca70
to
2181fe6
Compare
I think I've covered most of your comments @brenns10. I can always move the code out of Symbol if that's what we decide to do. |
I'd love to have something like My use-case is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry about the delay, I was on vacation for a month while you submitted this and have been perpetually behind on code review since then :) I agree with the other comments here that have the interface for this should be prog.source_info(address)
. I additionally left some comments about the implementation. Thanks for the contribution!
struct drgn_debug_info_module * | ||
drgn_debug_info_module_byaddress(struct drgn_debug_info *dbinfo, uint64_t addr) | ||
{ | ||
|
||
for (struct drgn_debug_info_module_table_iterator it = | ||
drgn_debug_info_module_table_first(&dbinfo->modules); it.entry; ) { | ||
struct drgn_debug_info_module *module = *it.entry; | ||
do { | ||
struct drgn_debug_info_module *next = module->next; | ||
if (!next) | ||
it = drgn_debug_info_module_table_next(it); | ||
if (addr >= module->start && addr <= module->end) | ||
return module; | ||
module = next; | ||
} while (module); | ||
} | ||
return NULL; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than adding this, you can look up the Dwfl_Module *
for an address with dwfl_addrmodule()
. If you need the struct drgn_debug_info_module *
, too, you can get it with dwfl_module_info()
. Here's an example:
Lines 89 to 96 in 330c71b
if (prog->dbinfo) { | |
Dwfl_Module *dwfl_module = dwfl_addrmodule(prog->dbinfo->dwfl, | |
pc - !regs->interrupted); | |
if (dwfl_module) { | |
void **userdatap; | |
dwfl_module_info(dwfl_module, &userdatap, NULL, NULL, | |
NULL, NULL, NULL, NULL); | |
struct drgn_debug_info_module *module = *userdatap; |
"could not locate module from function address"); | ||
|
||
|
||
Dwfl_Line *line = dwfl_module_getsrc(dim->dwfl_module, sym_address); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dwfl_module_getsrc()
doesn't work on binaries compiled by Clang, because Clang doesn't generate .debug_aranges
by default and dwfl_module_getsrc()
only checks .debug_aranges
. I would really like this to work with Clang as well. I had to work around this same problem in add17a9. The difference here is that we don't have the CU containing the address yet. We need a function like:
struct drgn_error *
drgn_debug_info_module_find_dwarf_cu(struct drgn_debug_info_module *module,
uint64_t pc, uint64_t *bias_ret,
Dwarf_Die *cu_die_ret)
Which would be very similar to the beginning of drgn_debug_info_module_find_dwarf_scopes()
, just without needing to iterate into children of the CU DIE. (Let me know if you need help factoring that out.) Then, you can do something similar to drgn_stack_frame_source()
:
Lines 312 to 331 in 330c71b
Dwarf_Addr bias; | |
if (!dwfl_module_getdwarf(dwfl_module, &bias)) | |
return NULL; | |
pc.value = pc.value - bias - !regs->interrupted; | |
Dwarf_Die *scopes = trace->frames[frame].scopes; | |
size_t num_scopes = trace->frames[frame].num_scopes; | |
Dwarf_Die cu_die; | |
if (!dwarf_cu_die(scopes[num_scopes - 1].cu, &cu_die, NULL, | |
NULL, NULL, NULL, NULL, NULL)) | |
return NULL; | |
Dwarf_Line *line = dwarf_getsrc_die(&cu_die, pc.value); | |
if (!line) | |
return NULL; | |
if (line_ret) | |
dwarf_lineno(line, line_ret); | |
if (column_ret) | |
dwarf_linecol(line, column_ret); | |
return dwarf_linesrc(line, NULL, NULL); |
int lineno, linecol; | ||
if ((src = dwfl_lineinfo(line, &sym_address, &lineno, &linecol, | ||
NULL, NULL)) != NULL) { | ||
strncpy(src_file_ret, src, size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather that we just strdup()
this and leave it up to the caller to free()
it instead of requiring a size.
For function symbols, provide the source code file, optional line number, and optional column. This is useful for noting the source code file/line/col when disassembling a function. In the code, look up the module by the function Symbol address, and use the module to help get the line number.
First drgn PR, so was unsure how to develop a test for this... let me know. Also how to create drgn_Symbol_source_DOC instead of putting in a string directly? Thanks!