mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-30 10:45:40 +03:00 
			
		
		
		
	mach: Add __mach_setup_thread_call ()
This is just like mach_setup_thread (), but it's suitable for making the thread call a function correctly, as opposed to explicitly setting the thread's stack and instruction pointers to the given values. Internally, it uses MACHINE_THREAD_STATE_SETUP_CALL. Unlike mach_setup_thread (), which is exported via mach.h for the benefit of the Hurd exec server, __mach_setup_thread_call () is private to glibc for the time being. Signed-off-by: Sergey Bugaev <bugaevc@gmail.com> Message-Id: <20230517191436.73636-5-bugaevc@gmail.com>
This commit is contained in:
		
				
					committed by
					
						 Samuel Thibault
						Samuel Thibault
					
				
			
			
				
	
			
			
			
						parent
						
							be9c1b9cf4
						
					
				
				
					commit
					01f317e98f
				
			| @@ -88,7 +88,11 @@ extern FILE *mach_open_devstream (mach_port_t device_port, const char *mode); | |||||||
|    If STACK_BASE is not null it is filled in with the chosen stack base. |    If STACK_BASE is not null it is filled in with the chosen stack base. | ||||||
|    If STACK_SIZE is not null it is filled in with the chosen stack size. |    If STACK_SIZE is not null it is filled in with the chosen stack size. | ||||||
|    Regardless, an extra page of red zone is allocated off the end; this |    Regardless, an extra page of red zone is allocated off the end; this | ||||||
|    is not included in *STACK_SIZE.  */ |    is not included in *STACK_SIZE. | ||||||
|  |  | ||||||
|  |    Mote: this function is unsuitable for setting up the thread to call a | ||||||
|  |    function at PC, since the architecture ABI may impose additional | ||||||
|  |    requirements beyond setting PC and stack.  */ | ||||||
| kern_return_t __mach_setup_thread (task_t task, thread_t thread, void *pc, | kern_return_t __mach_setup_thread (task_t task, thread_t thread, void *pc, | ||||||
| 				   vm_address_t *stack_base, | 				   vm_address_t *stack_base, | ||||||
| 				   vm_size_t *stack_size); | 				   vm_size_t *stack_size); | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ | |||||||
|    <https://www.gnu.org/licenses/>.  */ |    <https://www.gnu.org/licenses/>.  */ | ||||||
|  |  | ||||||
| #include <mach.h> | #include <mach.h> | ||||||
|  | #include <mach/setup-thread.h> | ||||||
| #include <thread_state.h> | #include <thread_state.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <mach/machine/vm_param.h> | #include <mach/machine/vm_param.h> | ||||||
| @@ -24,6 +25,58 @@ | |||||||
|  |  | ||||||
| #define	STACK_SIZE	(16 * 1024 * 1024) /* 16MB, arbitrary.  */ | #define	STACK_SIZE	(16 * 1024 * 1024) /* 16MB, arbitrary.  */ | ||||||
|  |  | ||||||
|  | static kern_return_t | ||||||
|  | mach_setup_thread_impl (task_t task, thread_t thread, int is_call, | ||||||
|  | 			void *pc, vm_address_t *stack_base, | ||||||
|  | 			vm_size_t *stack_size) | ||||||
|  | { | ||||||
|  |   kern_return_t error; | ||||||
|  |   struct machine_thread_state ts; | ||||||
|  |   mach_msg_type_number_t tssize = MACHINE_THREAD_STATE_COUNT; | ||||||
|  |   vm_address_t stack; | ||||||
|  |   vm_size_t size; | ||||||
|  |   int anywhere; | ||||||
|  |  | ||||||
|  |   memset (&ts, 0, sizeof (ts)); | ||||||
|  |  | ||||||
|  |   size = stack_size ? *stack_size ? : STACK_SIZE : STACK_SIZE; | ||||||
|  |   stack = stack_base ? *stack_base ? : 0 : 0; | ||||||
|  |   anywhere = !stack_base || !*stack_base; | ||||||
|  |  | ||||||
|  |   error = __vm_allocate (task, &stack, size + __vm_page_size, anywhere); | ||||||
|  |   if (error) | ||||||
|  |     return error; | ||||||
|  |  | ||||||
|  |   if (stack_size) | ||||||
|  |     *stack_size = size; | ||||||
|  |  | ||||||
|  | #ifdef STACK_GROWTH_DOWN | ||||||
|  |   if (stack_base) | ||||||
|  |     *stack_base = stack + __vm_page_size; | ||||||
|  | #elif defined (STACK_GROWTH_UP) | ||||||
|  |   if (stack_base) | ||||||
|  |     *stack_base = stack; | ||||||
|  |   stack += size; | ||||||
|  | #else | ||||||
|  |   #error stack direction unknown | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |   if (is_call) | ||||||
|  |     MACHINE_THREAD_STATE_SETUP_CALL (&ts, *stack_base, size, pc); | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       MACHINE_THREAD_STATE_SET_PC (&ts, pc); | ||||||
|  |       MACHINE_THREAD_STATE_SET_SP (&ts, *stack_base, size); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   /* Create the red zone.  */ | ||||||
|  |   if (error = __vm_protect (task, stack, __vm_page_size, 0, VM_PROT_NONE)) | ||||||
|  |     return error; | ||||||
|  |  | ||||||
|  |   return __thread_set_state (thread, MACHINE_NEW_THREAD_STATE_FLAVOR, | ||||||
|  | 			     (natural_t *) &ts, tssize); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Give THREAD a stack and set it to run at PC when resumed. | /* Give THREAD a stack and set it to run at PC when resumed. | ||||||
|    If *STACK_SIZE is nonzero, that size of stack is allocated. |    If *STACK_SIZE is nonzero, that size of stack is allocated. | ||||||
|    If *STACK_BASE is nonzero, that stack location is used. |    If *STACK_BASE is nonzero, that stack location is used. | ||||||
| @@ -36,49 +89,18 @@ kern_return_t | |||||||
| __mach_setup_thread (task_t task, thread_t thread, void *pc, | __mach_setup_thread (task_t task, thread_t thread, void *pc, | ||||||
| 		     vm_address_t *stack_base, vm_size_t *stack_size) | 		     vm_address_t *stack_base, vm_size_t *stack_size) | ||||||
| { | { | ||||||
|   kern_return_t error; |   return mach_setup_thread_impl (task, thread, 0, pc, stack_base, stack_size); | ||||||
|   struct machine_thread_state ts; |  | ||||||
|   mach_msg_type_number_t tssize = MACHINE_THREAD_STATE_COUNT; |  | ||||||
|   vm_address_t stack; |  | ||||||
|   vm_size_t size; |  | ||||||
|   int anywhere; |  | ||||||
|  |  | ||||||
|   size = stack_size ? *stack_size ? : STACK_SIZE : STACK_SIZE; |  | ||||||
|   stack = stack_base ? *stack_base ? : 0 : 0; |  | ||||||
|   anywhere = !stack_base || !*stack_base; |  | ||||||
|  |  | ||||||
|   error = __vm_allocate (task, &stack, size + __vm_page_size, anywhere); |  | ||||||
|   if (error) |  | ||||||
|     return error; |  | ||||||
|  |  | ||||||
|   if (stack_size) |  | ||||||
|     *stack_size = size; |  | ||||||
|  |  | ||||||
|   memset (&ts, 0, sizeof (ts)); |  | ||||||
|   MACHINE_THREAD_STATE_SET_PC (&ts, pc); |  | ||||||
| #ifdef STACK_GROWTH_DOWN |  | ||||||
|   if (stack_base) |  | ||||||
|     *stack_base = stack + __vm_page_size; |  | ||||||
|   ts.SP = stack + __vm_page_size + size; |  | ||||||
| #elif defined (STACK_GROWTH_UP) |  | ||||||
|   if (stack_base) |  | ||||||
|     *stack_base = stack; |  | ||||||
|   ts.SP = stack; |  | ||||||
|   stack += size; |  | ||||||
| #else |  | ||||||
|   #error stack direction unknown |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|   /* Create the red zone.  */ |  | ||||||
|   if (error = __vm_protect (task, stack, __vm_page_size, 0, VM_PROT_NONE)) |  | ||||||
|     return error; |  | ||||||
|  |  | ||||||
|   return __thread_set_state (thread, MACHINE_NEW_THREAD_STATE_FLAVOR, |  | ||||||
| 			     (natural_t *) &ts, tssize); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| weak_alias (__mach_setup_thread, mach_setup_thread) | weak_alias (__mach_setup_thread, mach_setup_thread) | ||||||
|  |  | ||||||
|  | kern_return_t | ||||||
|  | __mach_setup_thread_call (task_t task, thread_t thread, void *pc, | ||||||
|  | 			  vm_address_t *stack_base, vm_size_t *stack_size) | ||||||
|  | { | ||||||
|  |   return mach_setup_thread_impl (task, thread, 1, pc, stack_base, stack_size); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Give THREAD a TLS area.  */ | /* Give THREAD a TLS area.  */ | ||||||
| kern_return_t | kern_return_t | ||||||
| __mach_setup_tls (thread_t thread) | __mach_setup_tls (thread_t thread) | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								mach/setup-thread.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								mach/setup-thread.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | /* Setup a Mach thread. | ||||||
|  |    Copyright (C) 1993-2023 Free Software Foundation, Inc. | ||||||
|  |    This file is part of the GNU C Library. | ||||||
|  |  | ||||||
|  |    The GNU C Library is free software; you can redistribute it and/or | ||||||
|  |    modify it under the terms of the GNU Lesser General Public | ||||||
|  |    License as published by the Free Software Foundation; either | ||||||
|  |    version 2.1 of the License, or (at your option) any later version. | ||||||
|  |  | ||||||
|  |    The GNU C Library is distributed in the hope that it will be useful, | ||||||
|  |    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||||
|  |    Lesser General Public License for more details. | ||||||
|  |  | ||||||
|  |    You should have received a copy of the GNU Lesser General Public | ||||||
|  |    License along with the GNU C Library; if not, see | ||||||
|  |    <https://www.gnu.org/licenses/>.  */ | ||||||
|  |  | ||||||
|  | #ifndef	_MACH_SETUP_THREAD_H | ||||||
|  |  | ||||||
|  | #define	_MACH_SETUP_THREAD_H	1 | ||||||
|  |  | ||||||
|  | #include <mach.h> | ||||||
|  |  | ||||||
|  | /* Like mach_setup_thread (), but suitable for setting up function | ||||||
|  |    calls.  */ | ||||||
|  | kern_return_t __mach_setup_thread_call (task_t task, thread_t thread, | ||||||
|  | 					void *function, | ||||||
|  | 					vm_address_t *stack_base, | ||||||
|  | 					vm_size_t *stack_size); | ||||||
|  |  | ||||||
|  | #endif	/* mach/setup-thread.h */ | ||||||
		Reference in New Issue
	
	Block a user