forked from enlightenment/efl
Normally when debugging Eo with gdb you can just use any of the internal eo functions to resolve the id to its internal pointer. However, when loading a coredump you can't execute any code, not even the id resolve code. This change adds a gdb function that resolves the id to its pointer form without executing any code in the process space. This plugin is essentially the id resolve code written in python as a gdb function. Usage: Print the pointer: (gdb) print $eo_resolve(obj) $1 = (_Eo_Object *) 0x5555559bbe70 Use it directly (e.g. to print the class name): (gdb) $eo_resolve(obj)->klass->desc.name This plugin requires that the coredump would be loaded with the exact same libeo.so binary (or at least one that hasn't changed eo internals), and that the debug symbols for libeo.so would be available for gdb to use. Note: This feature is incomplete and only resolves IDs that are owned by the main thread and in the main domain. This is not a big issue at the moment, because almost all of our IDs are like that. @featuredevs/lorddrew/edje_edit_in_memory
parent
3dd51bf53d
commit
79d76fb25e
2 changed files with 108 additions and 2 deletions
@ -1,4 +1,104 @@ |
||||
# Implement eo_break that'll break on a macro/subid/whatever. |
||||
|
||||
import gdb |
||||
|
||||
""" |
||||
All of this script relies heavily on Eo internals and will break if they |
||||
change. Need to make sure this is always in sync. |
||||
""" |
||||
|
||||
ptr_size = int(gdb.parse_and_eval('sizeof(void *)')) |
||||
|
||||
SHIFT_MID_TABLE_ID = 0x30 |
||||
MASK_MID_TABLE_ID = 0x7ff |
||||
SHIFT_TABLE_ID = 0x25 |
||||
MASK_TABLE_ID = 0x7ff |
||||
SHIFT_ENTRY_ID = 0x1a |
||||
MASK_ENTRY_ID = 0x7ff |
||||
MASK_GENERATIONS = 0x3ffffff |
||||
MASK_OBJ_TAG = 0x4000000000000000 |
||||
|
||||
if ptr_size == 4: |
||||
# 32 bits |
||||
BITS_MID_TABLE_ID = 5 |
||||
BITS_TABLE_ID = 5 |
||||
BITS_ENTRY_ID = 11 |
||||
BITS_GENERATION_COUNTER = 6 |
||||
BITS_DOMAIN = 2 |
||||
BITS_CLASS = 1 |
||||
REF_TAG_SHIFT = 30 |
||||
SUPER_TAG_SHIFT = 31 |
||||
DROPPED_TABLES = 0 |
||||
DROPPED_ENTRIES = 4 |
||||
else: |
||||
# 64 bits |
||||
BITS_MID_TABLE_ID = 11 |
||||
BITS_TABLE_ID = 11 |
||||
BITS_ENTRY_ID = 11 |
||||
BITS_GENERATION_COUNTER = 26 |
||||
BITS_DOMAIN = 2 |
||||
BITS_CLASS = 1 |
||||
REF_TAG_SHIFT = 62 |
||||
SUPER_TAG_SHIFT = 63 |
||||
DROPPED_TABLES = 2 |
||||
DROPPED_ENTRIES = 3 |
||||
|
||||
# /* Shifts macros to manipulate the Eo id */ |
||||
SHIFT_DOMAIN = (BITS_MID_TABLE_ID + BITS_TABLE_ID + |
||||
BITS_ENTRY_ID + BITS_GENERATION_COUNTER) |
||||
SHIFT_MID_TABLE_ID = (BITS_TABLE_ID + |
||||
BITS_ENTRY_ID + BITS_GENERATION_COUNTER) |
||||
SHIFT_TABLE_ID = (BITS_ENTRY_ID + BITS_GENERATION_COUNTER) |
||||
SHIFT_ENTRY_ID = (BITS_GENERATION_COUNTER) |
||||
|
||||
# /* Maximum ranges */ |
||||
MAX_DOMAIN = (1 << BITS_DOMAIN) |
||||
MAX_MID_TABLE_ID = (1 << BITS_MID_TABLE_ID) |
||||
MAX_TABLE_ID = ((1 << BITS_TABLE_ID) - DROPPED_TABLES) |
||||
MAX_ENTRY_ID = ((1 << BITS_ENTRY_ID) - DROPPED_ENTRIES) |
||||
MAX_GENERATIONS = (1 << BITS_GENERATION_COUNTER) |
||||
|
||||
# /* Masks */ |
||||
MASK_DOMAIN = (MAX_DOMAIN - 1) |
||||
MASK_MID_TABLE_ID = (MAX_MID_TABLE_ID - 1) |
||||
MASK_TABLE_ID = ((1 << BITS_TABLE_ID) - 1) |
||||
MASK_ENTRY_ID = ((1 << BITS_ENTRY_ID) - 1) |
||||
MASK_GENERATIONS = (MAX_GENERATIONS - 1) |
||||
MASK_OBJ_TAG = (1 << (REF_TAG_SHIFT)) |
||||
|
||||
|
||||
null_ptr = gdb.parse_and_eval('(_Eo_Object *) 0') |
||||
|
||||
|
||||
class Eo_resolve(gdb.Function): |
||||
def __init__(self): |
||||
gdb.Function.__init__(self, 'eo_resolve') |
||||
|
||||
def invoke(self, arg): |
||||
obj_id = int(arg) |
||||
|
||||
mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID |
||||
table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID |
||||
entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID |
||||
tag_bit = (obj_id) & MASK_OBJ_TAG |
||||
generation = obj_id & MASK_GENERATIONS |
||||
|
||||
if (obj_id == 0) or (tag_bit == 0): |
||||
gdb.write('Pointer is NULL or not a valid object.\n') |
||||
return null_ptr |
||||
|
||||
entries = gdb.parse_and_eval('_eo_gdb_main_domain->tables[0]->' + |
||||
'eo_ids_tables[{0}]'.format(mid_table_id)) |
||||
|
||||
if int(entries) == 0: |
||||
gdb.write('Pointer is not a valid object.\n') |
||||
return null_ptr |
||||
|
||||
entry = entries[table_id]['entries'][entry_id] |
||||
|
||||
if (not entry['active']) or (int(entry['generation']) != generation): |
||||
gdb.write('Pointer is no longer active.\n') |
||||
return null_ptr |
||||
|
||||
return entry['ptr'] |
||||
|
||||
|
||||
Eo_resolve() |
||||
|
Loading…
Reference in new issue