Mac内核XNU的mach_vm子系统某个函数的代码逻辑
mach子系统包括了很多内核功能的实现,比如VM子系统(内存管理)、host子系统(主机硬件信息的处理)、thread子系统(thread相关实现)、exc子系统(异常处理相关),下面跟踪一下mach_vm子系统的mach_vm_allocate函数。
(1)最顶层函数mach_vm_allocate:
它的实现,调用了两个函数(要么这个,要么另一个):
------ xnu/libsyscall/mach/mach_vm.c ------
kern_return_t mach_vm_allocate(
mach_port_name_t target,
mach_vm_address_t *address,
mach_vm_size_t size,
int flags)
{
kern_return_t rv;
rv = _kernelrpc_mach_vm_allocate_trap(target, address, size, flags);
if (rv == MACH_SEND_INVALID_DEST)
rv = _kernelrpc_mach_vm_allocate(target, address, size, flags);
if (__syscall_logger) {
int userTagFlags = flags & VM_FLAGS_ALIAS_MASK;
__syscall_logger(stack_logging_type_vm_allocate | userTagFlags, (uintptr_t)target, (uintptr_t)size, 0, (uintptr_t)*address, 0);
}
return (rv);
}
(1.0)看第一个函数的实现
函数_kernelrpc_mach_vm_allocate的实现在哪里呢?检索了xnu/osfmk/下面的代码,只有一个:
------ xnu/osfmk/ipc/mach_vm_kernelrpc.c ------
int _kernelrpc_mach_vm_allocate_trap(struct _kernelrpc_mach_vm_allocate_trap_args *args)
{
mach_vm_offset_t addr;
task_t task = port_name_to_task(args->target);
int rv = MACH_SEND_INVALID_DEST;
if (task != current_task())
goto done;
if (copyin(args->addr, (char *)&addr, sizeof (addr)))
goto done;
rv = mach_vm_allocate(task->map, &addr, args->size, args->flags);
if (rv == KERN_SUCCESS)
rv = copyout(&addr, args->addr, sizeof (addr));
done:
if (task)
task_deallocate(task);
return (rv);
}
其中调用的函数mach_vm_allocate也有实现如下,可以函数调用到了最终的那个:
------ xnu/osfmk/vm/vm_user.c ------
/*
* mach_vm_allocate allocates "zero fill" memory in the specfied
* map.
*/
kern_return_t mach_vm_allocate(
vm_map_t map,
mach_vm_offset_t *addr,
mach_vm_size_t size,
int flags)
{
vm_map_offset_t map_addr;
vm_map_size_t map_size;
kern_return_t result;
boolean_t anywhere;
/* filter out any kernel-only flags */
if (flags & ~VM_FLAGS_USER_ALLOCATE)
return KERN_INVALID_ARGUMENT;
if (map == VM_MAP_NULL)
return(KERN_INVALID_ARGUMENT);
if (size == 0) {
*addr = 0;
return(KERN_SUCCESS);
}
anywhere = ((VM_FLAGS_ANYWHERE & flags) != 0);
if (anywhere) {
/*
* No specific address requested, so start candidate address
* search at the minimum address in the map. However, if that
* minimum is 0, bump it up by PAGE_SIZE. We want to limit
* allocations of PAGEZERO to explicit requests since its
* normal use is to catch dereferences of NULL and many
* applications also treat pointers with a value of 0 as
* special and suddenly having address 0 contain useable
* memory would tend to confuse those applications.
*/
map_addr = vm_map_min(map);
if (map_addr == 0)
map_addr += VM_MAP_PAGE_SIZE(map);
} else
map_addr = vm_map_trunc_page(*addr,
VM_MAP_PAGE_MASK(map));
map_size = vm_map_round_page(size,
VM_MAP_PAGE_MASK(map));
if (map_size == 0) {
return(KERN_INVALID_ARGUMENT);
}
result = vm_map_enter(
map,
&map_addr,
map_size,
(vm_map_offset_t)0,
flags,
VM_OBJECT_NULL,
(vm_object_offset_t)0,
FALSE,
VM_PROT_DEFAULT,
VM_PROT_ALL,
VM_INHERIT_DEFAULT);
*addr = map_addr;
return(result);
}
(2)mach_vm子系统的实现分为两部分:
mach_vmServer.c和mach_vmUser.c,分别实现了内核中mach msg消息接收和发送的各个API。
基本逻辑是:调用mach_vmUser.c实现的API,接收到消息后mach_vmServer.c的对应函数被调用,真正完成一些事情。
说明一下,所有子系统的***Server.c和***User.c代码都是通过MIG由***.defs生成。
(3)mach_vm提供的头文件:
头文件中申明了很多个mach_vm相关的函数,下面代码片段是_kernelrpc_mach_vm_allocate。
------ xnu/osfmk/mach/mach_vm.h ------
/* Routine _kernelrpc_mach_vm_allocate */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t _kernelrpc_mach_vm_allocate
(
vm_map_t target,
mach_vm_address_t *address,
mach_vm_size_t size,
int flags
);
(4)mach msg消息发送:
下面是一个“类似系统调用”的函数(或者某个系统调用会间接调用这个函数),用于向mach_vm子系统发送mach msg消息请求某个服务(可以当作RPC)。
------ xnu/osfmk/mach/mach_vmUser.c ------
/* Routine _kernelrpc_mach_vm_allocate */
mig_external kern_return_t _kernelrpc_mach_vm_allocate
(
vm_map_t target,
mach_vm_address_t *address,
mach_vm_size_t size,
int flags
)
{
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_vm_address_t address;
mach_vm_size_t size;
int flags;
} Request;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_vm_address_t address;
mach_msg_trailer_t trailer;
} Reply;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_vm_address_t address;
} __Reply;
#ifdef __MigPackStructs
#pragma pack()
#endif
/*
* typedef struct {
* mach_msg_header_t Head;
* NDR_record_t NDR;
* kern_return_t RetCode;
* } mig_reply_error_t;
*/
union {
Request In;
Reply Out;
} Mess;
Request *InP = &Mess.In;
Reply *Out0P = &Mess.Out;
mach_msg_return_t msg_result;
#ifdef __MIG_check__Reply___kernelrpc_mach_vm_allocate_t__defined
kern_return_t check_result;
#endif /* __MIG_check__Reply___kernelrpc_mach_vm_allocate_t__defined */
__DeclareSendRpc(4800, "_kernelrpc_mach_vm_allocate")
InP->NDR = NDR_record;
InP->address = *address;
InP->size = size;
InP->flags = flags;
InP->Head.msgh_bits =
MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
/* msgh_size passed as argument */
InP->Head.msgh_request_port = target;
InP->Head.msgh_reply_port = mig_get_reply_port();
InP->Head.msgh_id = 4800;
__BeforeSendRpc(4800, "_kernelrpc_mach_vm_allocate")
msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
__AfterSendRpc(4800, "_kernelrpc_mach_vm_allocate")
if (msg_result != MACH_MSG_SUCCESS) {
__MachMsgErrorWithoutTimeout(msg_result);
{ return msg_result; }
}
#if defined(__MIG_check__Reply___kernelrpc_mach_vm_allocate_t__defined)
check_result = __MIG_check__Reply___kernelrpc_mach_vm_allocate_t((__Reply___kernelrpc_mach_vm_allocate_t *)Out0P);
if (check_result != MACH_MSG_SUCCESS)
{ return check_result; }
#endif /* defined(__MIG_check__Reply___kernelrpc_mach_vm_allocate_t__defined) */
*address = Out0P->address;
return KERN_SUCCESS;
}
(5)mach_vmServer.c中的mach msg消息接收:
------ xnu/osfmk/mach/mach_vmServer.c ------
/* Description of this subsystem, for use in direct RPC */
const struct mach_vm_subsystem {
mig_server_routine_t server; /* Server routine */
mach_msg_id_t start; /* Min routine number */
mach_msg_id_t end; /* Max routine number + 1 */
unsigned int maxsize; /* Max msg size */
vm_address_t reserved; /* Reserved */
struct routine_descriptor /*Array of routine descriptors */
routine[20];
} mach_vm_subsystem = {
mach_vm_server_routine,
4800,
4820,
(mach_msg_size_t)sizeof(union __ReplyUnion__mach_vm_subsystem),
(vm_address_t)0,
{
{ (mig_impl_routine_t) 0,
(mig_stub_routine_t) _X_kernelrpc_mach_vm_allocate, 5, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply___kernelrpc_mach_vm_allocate_t)},
{ (mig_impl_routine_t) 0,
(mig_stub_routine_t) _X_kernelrpc_mach_vm_deallocate, 5, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply___kernelrpc_mach_vm_deallocate_t)},
{ (mig_impl_routine_t) 0,
(mig_stub_routine_t) _X_kernelrpc_mach_vm_protect, 7, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply___kernelrpc_mach_vm_protect_t)},
{ (mig_impl_routine_t) 0,
(mig_stub_routine_t) _Xmach_vm_inherit, 6, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__mach_vm_inherit_t)},
{ (mig_impl_routine_t) 0,
(mig_stub_routine_t) _X_kernelrpc_ma
解释一下上面的代码,声明并且实现了数据结构mach_vm_subsystem,其中第6个成员是一个数组,数组的元素是一个结构 ---routine_descriptor;routine_descriptor声明如下:
------ xnu/osfmk/mach/mig.h ------
struct routine_descriptor {
mig_impl_routine_t impl_routine; /* Server work func pointer */
mig_stub_routine_t stub_routine; /* Unmarshalling func pointer */
unsigned int argc; /* Number of argument words */
unsigned int descr_count; /* Number complex descriptors */
routine_arg_descriptor_t
arg_descr; /* pointer to descriptor array*/
unsigned int max_reply_msg; /* Max size for reply msg */
};
typedef struct routine_descriptor *routine_descriptor_t;
typedef struct routine_descriptor mig_routine_descriptor;
typedef mig_routine_descriptor *mig_routine_descriptor_t;
(6)跟踪mach_vm_subsystem中_X_kernelrpc_mach_vm_allocate的实现
------ xnu/osfmk/mach/mach_vmServer.c ------
/* Routine _kernelrpc_mach_vm_allocate */
mig_internal novalue _X_kernelrpc_mach_vm_allocate
(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_vm_address_t address;
mach_vm_size_t size;
int flags;
mach_msg_trailer_t trailer;
} Request;
#ifdef __MigPackStructs
#pragma pack()
#endif
typedef __Request___kernelrpc_mach_vm_allocate_t __Request;
typedef __Reply___kernelrpc_mach_vm_allocate_t Reply;
/*
* typedef struct {
* mach_msg_header_t Head;
* NDR_record_t NDR;
* kern_return_t RetCode;
* } mig_reply_error_t;
*/
Request *In0P = (Request *) InHeadP;
Reply *OutP = (Reply *) OutHeadP;
#ifdef __MIG_check__Request___kernelrpc_mach_vm_allocate_t__defined
kern_return_t check_result;
#endif /* __MIG_check__Request___kernelrpc_mach_vm_allocate_t__defined */
__DeclareRcvRpc(4800, "_kernelrpc_mach_vm_allocate")
__BeforeRcvRpc(4800, "_kernelrpc_mach_vm_allocate")
#if defined(__MIG_check__Request___kernelrpc_mach_vm_allocate_t__defined)
check_result = __MIG_check__Request___kernelrpc_mach_vm_allocate_t((__Request *)In0P);
if (check_result != MACH_MSG_SUCCESS)
{ MIG_RETURN_ERROR(OutP, check_result); }
#endif /* defined(__MIG_check__Request___kernelrpc_mach_vm_allocate_t__defined) */
OutP->RetCode = _kernelrpc_mach_vm_allocate(In0P->Head.msgh_request_port, &In0P->address, In0P->size, In0P->flags);
if (OutP->RetCode != KERN_SUCCESS) {
MIG_RETURN_ERROR(OutP, OutP->RetCode);
}
OutP->NDR = NDR_record;
OutP->address = In0P->address;
OutP->Head.msgh_size = (mach_msg_size_t)(sizeof(Reply));
__AfterRcvRpc(4800, "_kernelrpc_mach_vm_allocate")
}
(7)最终实现不见
找遍xnu项目代码,没有_kernelrpc_mach_vm_allocate的实现哦!
这里就是之前提到“死胡同”和“没下文”的地方!
说明:一个大工程,总有一些死代码,永远跑不到的地方,应该干掉却没有干掉,这个不影响系统功能