esp-idf/components/espcoredump/corefile/__init__.py

126 wiersze
4.2 KiB
Python

#
# Copyright 2021 Espressif Systems (Shanghai) CO., LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
__version__ = '0.4-dev'
import abc
import os
from abc import abstractmethod
from importlib import import_module
from future.utils import with_metaclass
try:
from typing import Optional, Tuple
except ImportError:
pass
IDF_PATH = os.path.normpath(os.getenv('IDF_PATH', '.'))
XTENSA_TARGETS = ['esp32', 'esp32s2']
RISCV_TARGETS = ['esp32c3']
SUPPORTED_TARGETS = XTENSA_TARGETS + RISCV_TARGETS
class ESPCoreDumpError(RuntimeError):
pass
class ESPCoreDumpLoaderError(ESPCoreDumpError):
pass
class BaseArchMethodsMixin(with_metaclass(abc.ABCMeta)): # type: ignore
@staticmethod
@abstractmethod
def get_registers_from_stack(data, grows_down):
# type: (bytes, bool) -> Tuple[list[int], Optional[dict[int, int]]]
"""
Parse stack data, growing up stacks are not supported for now.
:param data: stack data
:param grows_down: stack grow direction
:return: return tuple (regs, exception_regs)
"""
pass
@staticmethod
@abstractmethod
def build_prstatus_data(tcb_addr, task_regs): # type: (int, list[int]) -> str
"""
Build PrStatus note section
:param tcb_addr: tcb addr
:param task_regs: registers
:return: str
"""
pass
class BaseTargetMethods(with_metaclass(abc.ABCMeta, BaseArchMethodsMixin)): # type: ignore
UNKNOWN = 'unknown'
TARGET = UNKNOWN
COREDUMP_FAKE_STACK_START = 0x20000000
COREDUMP_FAKE_STACK_LIMIT = 0x30000000
COREDUMP_MAX_TASK_STACK_SIZE = 64 * 1024
def __init__(self): # type: () -> None
if self.TARGET == self.UNKNOWN:
raise ValueError('Please use the derived child-class with valid TARGET')
self._set_attr_from_soc_header()
def _set_attr_from_soc_header(self): # type: () -> None
module = import_module('corefile.soc_headers.{}'.format(self.TARGET))
for k, v in module.__dict__.items():
if k.startswith('SOC_'):
setattr(self, k, v)
def _esp_ptr_in_dram(self, addr): # type: (int) -> bool
return self.SOC_DRAM_LOW <= addr < self.SOC_DRAM_HIGH # type: ignore
def _esp_ptr_in_iram(self, addr): # type: (int) -> bool
return self.SOC_IRAM_LOW <= addr < self.SOC_IRAM_HIGH # type: ignore
def _esp_ptr_in_rtc_slow(self, addr): # type: (int) -> bool
return self.SOC_RTC_DATA_LOW <= addr < self.SOC_RTC_DATA_HIGH # type: ignore
def _esp_ptr_in_rtc_dram_fast(self, addr): # type: (int) -> bool
return self.SOC_RTC_DRAM_LOW <= addr < self.SOC_RTC_DRAM_HIGH # type: ignore
def tcb_is_sane(self, tcb_addr, tcb_size): # type: (int, int) -> bool
for func in [self._esp_ptr_in_dram,
self._esp_ptr_in_iram,
self._esp_ptr_in_rtc_slow,
self._esp_ptr_in_rtc_dram_fast]:
res = func(tcb_addr) and func(tcb_addr + tcb_size - 1)
if res:
return True
return False
def _esp_stack_ptr_in_dram(self, addr): # type: (int) -> bool
return not (addr < self.SOC_DRAM_LOW + 0x10
or addr > self.SOC_DRAM_HIGH - 0x10
or (addr & 0xF) != 0)
def stack_is_sane(self, stack_start, stack_end): # type: (int, int) -> bool
return (self._esp_stack_ptr_in_dram(stack_start)
and self._esp_ptr_in_dram(stack_end)
and stack_start < stack_end
and (stack_end - stack_start) < self.COREDUMP_MAX_TASK_STACK_SIZE)
def addr_is_fake(self, addr): # type: (int) -> bool
return (self.COREDUMP_FAKE_STACK_START <= addr < self.COREDUMP_FAKE_STACK_LIMIT
or addr > 2 ** 31 - 1)