def argument(p: WlPatterns, value_str: str) -> wl.Arg.Base: match = p.arg_re.match(value_str) if match: if match.group('int'): return wl.Arg.Int(int(value_str)) elif match.group('obj_id'): return wl.Arg.Object( wl.UnresolvedObject(int(match.group('obj_id')), match.group('obj_type')), False) elif match.group('new_id'): type_name: Optional[str] = match.group('new_type') if not type_name: type_name = None return wl.Arg.Object( wl.UnresolvedObject(int(match.group('new_id')), type_name), True) elif match.group('nil'): return wl.Arg.Null() elif match.group('str'): return wl.Arg.String(match.group('str')) elif match.group('float'): return wl.Arg.Float(float(value_str.replace(',', '.'))) elif match.group('fd'): return wl.Arg.Fd(int(match.group('fd'))) elif match.group('array'): return wl.Arg.Array() return wl.Arg.Unknown(value_str)
def received_message() -> Tuple[str, wl.Message]: frame = gdb.selected_frame() closure = frame.read_var('closure') wl_object = frame.read_var('target') parent_frame = frame.older() calling_func = parent_frame.name() # NOTE: closure->proxy is often null but technically undefined in the server case # Using it to detect server vs client works for the tests but fails on Mir if calling_func == 'dispatch_event': # Client connection new_id_is_actually_an_object = True wl_display = parent_frame.read_var('display') connection = _fast_access(wl_display, 'wl_display.connection') elif calling_func == 'wl_client_connection_data': # Server connection new_id_is_actually_an_object = False resource_type = lazy_get_wl_resource_ptr_type() resource = wl_object.cast(resource_type) connection = _fast_access(_fast_access(resource, 'wl_resource.client'), 'wl_client.connection') else: raise RuntimeError('Unknown libwayland calling function ' + calling_func) connection_id = connection_id_of(connection) object_id = int(_fast_access(closure, 'wl_closure.sender_id')) # wl_object is not a pointer, so can't use _fast_access() to get interface obj_type = _fast_access(wl_object['interface'], 'wl_interface.name').string() object = wl.UnresolvedObject(object_id, obj_type) message = extract_message(closure, object, False, new_id_is_actually_an_object) return connection_id, message
def sent_message() -> Tuple[str, wl.Message]: # We break on serialize_closure() (both wl_closure_send and wl_closure_queue call it, so just breaking on it # reduces breakpoints and improves performance). Everything we're interested in is in the parent frame though. frame = gdb.selected_frame().older() closure = frame.read_var('closure') # closure -> proxy is always null in wl_closure_send and wl_closure_queue connection = frame.read_var('connection') connection_id = connection_id_of(connection) object_id = int(_fast_access(closure, 'wl_closure.sender_id')) object = wl.UnresolvedObject(object_id, None) message = extract_message(closure, object, True, False) return connection_id, message
def message(raw: str) -> Tuple[str, wl.Message]: p = WlPatterns.lazy_get_instance() sent = True conn_id = 'PARSED' matches = p.out_msg_re.findall(raw) if not matches: sent = False matches = p.in_msg_re.findall(raw) if len(matches) != 1: raise RuntimeError(raw) match = matches[0] assert isinstance(match, tuple), repr(match) abs_timestamp = float(match[0].replace(',', '.')) / 1000.0 type_name = match[1] obj_id = int(match[2]) message_name = match[3] message_args_str = match[4] message_args = argument_list(p, message_args_str) return conn_id, wl.Message(abs_timestamp, wl.UnresolvedObject(obj_id, type_name), sent, message_name, message_args)
def extract_message(closure, object: wl.ObjectBase, is_sending: bool, new_id_is_actually_an_object: bool) -> wl.Message: '''Returns a tuple containing… Message Name: str, the message being called Arguments: list of wl.Arg ''' closure_message = _fast_access(closure, 'wl_closure.message') message_name = _fast_access(closure_message, 'wl_message.name').string() # The signiture is that stupid '2uufo?i' thing that has the type info signiture = _fast_access(closure_message, 'wl_message.signature').string() message_types = _fast_access(closure_message, 'wl_message.types') closure_args = _fast_access(closure, 'wl_closure.args') args: List[wl.Arg.Base] = [] i = 0 for c in signiture: # If its not a version number or '?' optional indicator if c in type_codes: # Pull out the right union member at the right index value = closure_args[i][c] if c == 'i' or c == 'u': args.append(wl.Arg.Int(int(value))) elif c == 'f': # Math is ripped out of wl_fixed_to_double() in libwayland f = float(gdb.parse_and_eval('(double)(void*)(((1023LL + 44LL) << 52) + (1LL << 51) + ' + str(value) + ') - (3LL << 43)')) args.append(wl.Arg.Float(f)) elif c == 's': if _is_null(value): str_val = '[null string]' else: str_val = value.string() args.append(wl.Arg.String(str_val)) elif c == 'a': size = int(value['size']) elems: List[wl.Arg.Base] = [] int_type = gdb.lookup_type('int') for i in range(size // int_type.sizeof): elem = value['data'].cast(int_type.pointer())[i] elems.append(wl.Arg.Int(int(elem))) args.append(wl.Arg.Array(elems)) elif c == 'h': args.append(wl.Arg.Fd(int(value))) elif c == 'o': arg_type = message_types[i] if _is_null(arg_type): arg_type_name = None else: arg_type_name = arg_type['name'].string() if _is_null(value): args.append(wl.Arg.Null(arg_type_name)) else: arg_id = int(_fast_access(value, 'wl_object.id')) args.append(wl.Arg.Object(wl.UnresolvedObject(arg_id, arg_type_name), False)) elif c == 'n': arg_type = message_types[i] if _is_null(arg_type): arg_type_name = None else: arg_type_name = arg_type['name'].string() if new_id_is_actually_an_object: arg_id = int(_fast_access(closure_args[i]['o'], 'wl_object.id')) else: arg_id = int(value) args.append(wl.Arg.Object(wl.UnresolvedObject(arg_id, arg_type_name), True)) else: raise RuntimeError('Invalid type code ' + c) i += 1 return wl.Message(time_now(), object, is_sending, message_name, tuple(args))