[docs]classStackAllocationMixin(PagedMemoryMixin):""" This mixin adds automatic allocation for a stack region based on the stack_end and stack_size parameters. """# TODO: multiple stacks. this scheme should scale p well# TODO tbh this should be handled by an actual fault handler in simos or something
[docs]defallocate_stack_pages(self,addr:int,size:int,**kwargs):""" Pre-allocates pages for the stack without triggering any logic related to reading from them. :param addr: The highest address that should be mapped :param size: The number of bytes to be allocated. byte 1 is the one at addr, byte 2 is the one before that, and so on. :return: A list of the new page objects """# weird off-by-ones here. we want to calculate the last byte requested, find its pageno, and then use that to# determine what the last page allocated will be and then how many pages are touchedpageno=addr//self.page_sizeifpageno!=self._red_pageno:raiseSimMemoryError("Trying to allocate stack space in a place that isn't the top of the stack")num=pageno-((addr-size+1)//self.page_size)+1result=[]for_inrange(num):new_red_pageno=(self._red_pageno-1)%((1<<self.state.arch.bits)//self.page_size)ifnew_red_pagenoinself._pages:raiseSimSegfaultException(self._red_pageno*self.page_size,"stack collided with heap")ifself._remaining_stackisnotNoneandself._remaining_stack<self.page_size:raiseSimSegfaultException(self._red_pageno*self.page_size,"exhausted stack quota")l.debug("Allocating new stack page at %#x",self._red_pageno*self.page_size)result.append(PagedMemoryMixin._initialize_default_page(self,self._red_pageno,permissions=self._stack_perms,**kwargs))self._pages[self._red_pageno]=result[-1]self._red_pageno=new_red_pagenoifself._remaining_stackisnotNone:self._remaining_stack-=self.page_sizereturnresult