mach子系統包括了不少內核功能的實現,好比VM子系統(內存管理)、host子系統(主機硬件信息的處理)、thread子系統(thread相關實現)、exc子系統(異常處理相關),下面跟蹤一下mach_vm子系統的mach_vm_allocate函數。
數組
它的實現,調用了兩個函數(要麼這個,要麼另外一個):數據結構
------ xnu/libsyscall/mach/mach_vm.c ------app
kern_return_t mach_vm_allocate(函數
mach_port_name_t target,ui
mach_vm_address_t *address,this
mach_vm_size_t size,spa
int flags)code
{orm
kern_return_t rv;server
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);
}
函數_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);
}
mach_vmServer.c和mach_vmUser.c,分別實現了內核中mach msg消息接收和發送的各個API。
基本邏輯是:調用mach_vmUser.c實現的API,接收到消息後mach_vmServer.c的對應函數被調用,真正完成一些事情。
說明一下,全部子系統的***Server.c和***User.c代碼都是經過MIG由***.defs生成。
頭文件中申明瞭不少個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
);
下面是一個「相似系統調用」的函數(或者某個系統調用會間接調用這個函數),用於向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;
}
------ 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;
------ 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")
}
找遍xnu項目代碼,沒有_kernelrpc_mach_vm_allocate的實現哦!
這裏就是以前提到「死衚衕」和「沒下文」的地方!
說明:一個大工程,總有一些死代碼,永遠跑不到的地方,應該幹掉卻沒有幹掉,這個不影響系統功能