1# 2# Copyright 2021 Espressif Systems (Shanghai) CO., LTD 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16 17__version__ = '0.4-dev' 18 19import abc 20import os 21from abc import abstractmethod 22from importlib import import_module 23 24from future.utils import with_metaclass 25 26try: 27 from typing import Optional, Tuple 28except ImportError: 29 pass 30 31IDF_PATH = os.path.normpath(os.getenv('IDF_PATH', '.')) 32XTENSA_TARGETS = ['esp32', 'esp32s2', 'esp32s3'] 33RISCV_TARGETS = ['esp32c3'] 34SUPPORTED_TARGETS = XTENSA_TARGETS + RISCV_TARGETS 35 36 37class ESPCoreDumpError(RuntimeError): 38 pass 39 40 41class ESPCoreDumpLoaderError(ESPCoreDumpError): 42 pass 43 44 45class BaseArchMethodsMixin(with_metaclass(abc.ABCMeta)): # type: ignore 46 @staticmethod 47 @abstractmethod 48 def get_registers_from_stack(data, grows_down): 49 # type: (bytes, bool) -> Tuple[list[int], Optional[dict[int, int]]] 50 """ 51 Parse stack data, growing up stacks are not supported for now. 52 :param data: stack data 53 :param grows_down: stack grow direction 54 :return: return tuple (regs, exception_regs) 55 """ 56 pass 57 58 @staticmethod 59 @abstractmethod 60 def build_prstatus_data(tcb_addr, task_regs): # type: (int, list[int]) -> str 61 """ 62 Build PrStatus note section 63 :param tcb_addr: tcb addr 64 :param task_regs: registers 65 :return: str 66 """ 67 pass 68 69 70class BaseTargetMethods(with_metaclass(abc.ABCMeta, BaseArchMethodsMixin)): # type: ignore 71 UNKNOWN = 'unknown' 72 TARGET = UNKNOWN 73 74 COREDUMP_FAKE_STACK_START = 0x20000000 75 COREDUMP_FAKE_STACK_LIMIT = 0x30000000 76 COREDUMP_MAX_TASK_STACK_SIZE = 64 * 1024 77 78 def __init__(self): # type: () -> None 79 if self.TARGET == self.UNKNOWN: 80 raise ValueError('Please use the derived child-class with valid TARGET') 81 82 self._set_attr_from_soc_header() 83 84 def _set_attr_from_soc_header(self): # type: () -> None 85 module = import_module('corefile.soc_headers.{}'.format(self.TARGET)) 86 for k, v in module.__dict__.items(): 87 if k.startswith('SOC_'): 88 setattr(self, k, v) 89 90 def _esp_ptr_in_dram(self, addr): # type: (int) -> bool 91 return self.SOC_DRAM_LOW <= addr < self.SOC_DRAM_HIGH # type: ignore 92 93 def _esp_ptr_in_iram(self, addr): # type: (int) -> bool 94 return self.SOC_IRAM_LOW <= addr < self.SOC_IRAM_HIGH # type: ignore 95 96 def _esp_ptr_in_rtc_slow(self, addr): # type: (int) -> bool 97 return self.SOC_RTC_DATA_LOW <= addr < self.SOC_RTC_DATA_HIGH # type: ignore 98 99 def _esp_ptr_in_rtc_dram_fast(self, addr): # type: (int) -> bool 100 return self.SOC_RTC_DRAM_LOW <= addr < self.SOC_RTC_DRAM_HIGH # type: ignore 101 102 def tcb_is_sane(self, tcb_addr, tcb_size): # type: (int, int) -> bool 103 for func in [self._esp_ptr_in_dram, 104 self._esp_ptr_in_iram, 105 self._esp_ptr_in_rtc_slow, 106 self._esp_ptr_in_rtc_dram_fast]: 107 res = func(tcb_addr) and func(tcb_addr + tcb_size - 1) 108 if res: 109 return True 110 return False 111 112 def _esp_stack_ptr_in_dram(self, addr): # type: (int) -> bool 113 return not (addr < self.SOC_DRAM_LOW + 0x10 114 or addr > self.SOC_DRAM_HIGH - 0x10 115 or (addr & 0xF) != 0) 116 117 def stack_is_sane(self, stack_start, stack_end): # type: (int, int) -> bool 118 return (self._esp_stack_ptr_in_dram(stack_start) 119 and self._esp_ptr_in_dram(stack_end) 120 and stack_start < stack_end 121 and (stack_end - stack_start) < self.COREDUMP_MAX_TASK_STACK_SIZE) 122 123 def addr_is_fake(self, addr): # type: (int) -> bool 124 return (self.COREDUMP_FAKE_STACK_START <= addr < self.COREDUMP_FAKE_STACK_LIMIT 125 or addr > 2 ** 31 - 1) 126