diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 0db76f3d5..4cd8e53f0 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -28,24 +28,33 @@ config MEMMAP_SMP to save some memory. (ToDo: Make this automatically depend on unicore support) config MEMMAP_TRACEMEM - bool "Use TRAX tracing feature" - default "n" - help - The ESP32 contains a feature which allows you to trace the execution path the processor - has taken through the program. This is stored in a chunk of 32K (16K for single-processor) - of memory that can't be used for general purposes anymore. Disable this if you do not know - what this is. + bool + default "n" config MEMMAP_TRACEMEM_TWOBANKS - bool "Reserve memory for tracing both pro as well as app cpu execution" + bool default "n" - depends on MEMMAP_TRACEMEM && MEMMAP_SMP + +config ESP32_TRAX + bool "Use TRAX tracing feature" + default "n" + select MEMMAP_TRACEMEM help The ESP32 contains a feature which allows you to trace the execution path the processor has taken through the program. This is stored in a chunk of 32K (16K for single-processor) of memory that can't be used for general purposes anymore. Disable this if you do not know what this is. +config ESP32_TRAX_TWOBANKS + bool "Reserve memory for tracing both pro as well as app cpu execution" + default "n" + depends on ESP32_TRAX && MEMMAP_SMP + select MEMMAP_TRACEMEM_TWOBANKS + help + The ESP32 contains a feature which allows you to trace the execution path the processor + has taken through the program. This is stored in a chunk of 32K (16K for single-processor) + of memory that can't be used for general purposes anymore. Disable this if you do not know + what this is. # Memory to reverse for trace, used in linker script config TRACEMEM_RESERVE_DRAM @@ -95,6 +104,45 @@ config ESP32_CORE_DUMP_LOG_LEVEL help Config core dump module logging level (0-5). +choice ESP32_APPTRACE_DESTINATION + prompt "AppTrace: destination" + default ESP32_APPTRACE_DEST_NONE + help + Select destination for application trace: trace memory, uart or none (to disable). + +config ESP32_APPTRACE_DEST_TRAX + bool "Trace memory" + select ESP32_APPTRACE_ENABLE +config ESP32_APPTRACE_DEST_UART + bool "UART" + select ESP32_APPTRACE_ENABLE +config ESP32_APPTRACE_DEST_NONE + bool "None" +endchoice + +config ESP32_APPTRACE_ENABLE + bool + depends on !ESP32_TRAX + select MEMMAP_TRACEMEM + select MEMMAP_TRACEMEM_TWOBANKS + default F + help + Enables/disable application tracing module. + +config ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO + int "AppTrace: Timeout for flushing last trace data to host on panic" + depends on ESP32_APPTRACE_ENABLE + default 4294967295 + help + Timeout for flushing last trace data to host in case of panic. In us. + +config ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TRAX_THRESH + int "AppTrace: Threshold for flushing last trace data to host on panic" + depends on ESP32_APPTRACE_DEST_TRAX + default 50 + help + Threshold for flushing last trace data to host on panic. In percents of TRAX memory block length. + # Not implemented and/or needs new silicon rev to work config MEMMAP_SPISRAM bool "Use external SPI SRAM chip as main memory" diff --git a/components/esp32/app_trace.c b/components/esp32/app_trace.c new file mode 100644 index 000000000..47b7a021e --- /dev/null +++ b/components/esp32/app_trace.c @@ -0,0 +1,994 @@ +// Copyright 2017 Espressif Systems (Shanghai) PTE 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. +// +// Hot It Works +// ************ + +// 1. Components Overview +// ====================== + +// Xtensa has useful feature: TRAX debug module. It allows recording program execution flow during run-time without disturbing CPU commands flow. +// Exectution flow data are written to configurable Trace RAM block. Besides accessing Trace RAM itself TRAX module also allows to read/write +// trace memory via its registers by means of JTAG, APB or ERI transactions. +// ESP32 has two Xtensa cores with separate TRAX modules on them and provides two special memory regions to be used as trace memory. +// ESP32 allows muxing access to trace memory blocks in such a way that while one block is accessed by CPUs another can be accessed via JTAG by host +// via reading/writing TRAX registers. Block muxing is configurable at run-time and allows switching trace memory blocks between +// accessors in round-robin fashion so they can read/write separate memory blocks without disturbing each other. +// This moduile implements application tracing feature based on above mechanisms. This feature allows to transfer arbitrary user data to +// host via JTAG with minimal impact on system performance. This module is implied to be used in the following tracing scheme. + +// ------>------ ----- (host components) ----- +// | | | | +// --------------- ----------------------- ----------------------- ---------------- ------ --------- ----------------- +// |apptrace user|-->|target tracing module|<--->|TRAX_MEM0 | TRAX_MEM1|---->|TRAX_DATA_REGS|<-->|JTAG|<--->|OpenOCD|-->|trace data file| +// --------------- ----------------------- ----------------------- ---------------- ------ --------- ----------------- +// | | | | +// | ------<------ ---------------- | +// |<------------------------------------------->|TRAX_CTRL_REGS|<---->| +// ---------------- + +// In general tracing happens in the following way. User aplication requests tracing module to send some data by calling esp_apptrace_buffer_get(), +// moduile allocates necessary buffer in current input trace block. Then user fills received buffer with data and calls esp_apptrace_buffer_put(). +// When current input trace block is filled with app data it is exposed to host and the second block becomes input one and buffer filling restarts. +// While target application fills one memory block host reads another block via JTAG. +// To control buffer switching and for other communication purposes this implementation uses some TRAX registers. It is safe since HW TRAX tracing +// can not be used along with application tracing feature so these registers are freely readable/writeable via JTAG from host and via ERI from ESP32 cores. +// So this implementation's target CPU overhead is produced only by calls to allocate/manage buffers and data copying. +// On host special OpenOCD command must be used to read trace data. + +// 2.1.1.1 TRAX Registers layout +// ============================= + +// This module uses two TRAX HW registers to communicate with host SW (OpenOCD). +// - Control register uses TRAX_DELAYCNT as storage. Only lower 24 bits of TRAX_DELAYCNT are writable. Control register has the following bitfields: +// | 31..XXXXXX..24 | 23 .(host_connect). 23| 22..(block_id)..15 | 14..(block_len)..0 | +// 14..0 bits - actual length of user data in trace memory block. Target updates it every time it fills memory block and exposes it to host. +// Host writes zero to this field when it finishes reading exposed block; +// 22..15 bits - trace memory block transfer ID. Block counter. It can overflow. Updated by target, host should not modify it. Actually can be 1-2 bits; +// 23 bit - 'host connected' flag. If zero then host is not connected and tracing module works in post-mortem mode, otherwise in streaming mode; +// - Status register uses TRAX_TRIGGERPC as storage. If this register is not zero then currentlly CPU is changing TRAX registers and +// this register holds address of the instruction which application will execute when it finishes with those registers modifications. +// See 'Targets Connection' setion for details. + +// 3. Modes of operation +// ===================== + +// This module supports two modes of operation: +// - Post-mortem mode. This is the default mode. In this mode application tracing module does not check whether host has read all the data from block +// exposed to it and switches block in any case. The mode does not need host interaction for operation and so can be useful when only the latest +// trace data are necessary, e.g. for analyzing crashes. On panic the latest data from current input block are exposed to host and host can read them. +// There is menuconfig option CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TRAX_THRESH which control the threshold for flushing data on panic. +// - Streaming mode. Tracing module enters this mode when host connects to targets and sets respective bit in control register. In this mode tracing +// module waits for specified time until host read all the data from exposed block. +// On panic tracing module waits (timeout is configured via menuconfig via ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO) for the host to read all data +// from the previously exposed block. + +// 4. Communication Protocol +// ========================= + +// 4.1 Trace Memory Blocks +// ^^^^^^^^^^^^^^^^^^^^^^^^^ + +// Communication is controlled via special register. Host periodically polls control register on each core to find out if there are any data avalable. +// When current input trace memory block is filled tracing module exposes block to host and updates block_len and block_id fields in control register. +// Host reads new register value and according to it starts reading data from exposed block. Meanwhile target starts filling another trace block. +// When host finishes reading the block it clears block_len field in control register indicating to target that it is ready to accept the next block. + +// 4.2 User Data Chunks Level +// -------------------------- + +// Since trace memory block is shared between user data chunks and data copying is performed on behalf of the API user (in its normal context) in +// multithreading environment it can happen that task/ISR which copies data is preempted by another high prio task/ISR. So it is possible situation +// that task/ISR will fail to complete filling its data chunk before the whole trace block is exposed to the host. To handle such conditions tracing +// module prepends all user data chunks with 4 bytes header which contains allocated buffer size and actual data length within it. OpenOCD command +// which reads application traces will report error when it will read incompleted user data block. + +// 4.3 Targets Connection/Disconnection +// ------------------------------------ + +// When host is going to start tracing in streaming mode it needs to put both ESP32 cores into initial state when 'host connected' bit is set +// on both cores. To accomplish this host halts both cores and sets this bit in TRAX registers. But target code can be halted in state when it has read control +// register but has not updated its value. To handle such situations target code indicates to the host that it is updating control register by writing +// non-zero value to status register. Actually it writes address of the instruction which it will execute when it finishes with +// the registers update. When target is halted during control register update host sets breakpoint at the address from status register and resumes CPU. +// After target code finishes with register update it is halted on breakpoint, host detects it and safely sets 'host connected' bit. When both cores +// are set up they are resumed. Tracing starts without further intrusion into CPUs work. +// When host is going to stop tracing in streaming mode it needs to disconnect targets. Disconnection process is done using the same algorithm +// as for connecting, but 'host connected' bits are cleared on ESP32 cores. + +// 5. Module Access Synchronization +// ================================ + +// Access to internal module's data is synchronized with custom mutex. Mutex is a wrapper for portMUX_TYPE and uses almost the same sync mechanism as in +// vPortCPUAcquireMutex/vPortCPUReleaseMutex. The mechanism uses S32C1I Xtensa instruction to implement exclusive access to module's data from tasks and +// ISRs running on both cores. Also custom mutex allows specifying timeout for locking operation. Locking routine checks underlaying mutex in cycle until +// it gets its ownership or timeout expires. The differences of application tracing module's mutex implementation from vPortCPUAcquireMutex/vPortCPUReleaseMutex are: +// - Support for timeouts. +// - Local IRQs for CPU which owns the mutex are disabled till the call to unlocking routine. This is made to avoid possible task's prio inversion. +// When low prio task takes mutex and enables local IRQs gets preempted by high prio task which in its turn can try to acquire mutex using infinite timeout. +// So no local task switch occurs when mutex is locked. But this does not apply to tasks on another CPU. +// WARNING: Priority inversion can happen when low prio task works on one CPU and medium and high prio tasks work on another. +// There are some differences how mutex behaves when it is used from task and ISR context when timeout is non-zero: +// - In task context when mutex can not be locked portYIELD() is called before check for timeout condition to alow othet tasks work on the same CPU. +// - In ISR context when mutex can not be locked nothing is done before expired time check. +// WARNING: Care must be taken when selecting timeout values for trace calls from ISRs. Tracing module does not care about watchdogs when waiting on internal locks +// and when waiting for host to complete previous block reading, so if wating timeout value exceedes watchdog's one it can lead to system reboot. + +// 6. Timeouts +// ------------ + +// Timeout mechanism is based on xthal_get_ccount() routine and supports timeout values in micorseconds. +// There are two situations when task/ISR can be delayed by tracing API call. Timeout mechanism takes into account both conditions: +// - Trace data are locked by another task/ISR. When wating on trace data lock. +// - Current TRAX memory input block is full when working in streaming mode (host is connected). When waiting for host to complete previous block reading. +// When wating for any of above conditions xthal_get_ccount() is called periodically to calculate time elapsed from trace API routine entry. When elapsed +// time exceeds specified timeout value operation is canceled and ESP_ERR_TIMEOUT code is returned. + +// ALSO SEE example usage of application tracing module in 'components/log/README.rst' + +#include +#include "soc/soc.h" +#include "soc/dport_reg.h" +#include "eri.h" +#include "trax.h" +#include "freertos/FreeRTOS.h" +#include "freertos/portmacro.h" +#include "freertos/semphr.h" +#include "freertos/task.h" +#include "soc/timer_group_struct.h" +#include "soc/timer_group_reg.h" +#include "esp_app_trace.h" + +#if CONFIG_ESP32_APPTRACE_ENABLE +#define ESP_APPTRACE_DEBUG_STATS_ENABLE 0 +#define ESP_APPTRACE_BUF_HISTORY_DEPTH (16*100) + +#define ESP_APPTRACE_MAX_VPRINTF_ARGS 256 + +#define ESP_APPTRACE_PRINT_LOCK_NONE 0 +#define ESP_APPTRACE_PRINT_LOCK_SEM 1 +#define ESP_APPTRACE_PRINT_LOCK_MUX 2 +#define ESP_APPTRACE_PRINT_LOCK ESP_APPTRACE_PRINT_LOCK_NONE//ESP_APPTRACE_PRINT_LOCK_SEM + +#define ESP_APPTRACE_USE_LOCK_SEM 0 // 1 - semaphore (now may be broken), 0 - portMUX_TYPE + +#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE +#include "esp_log.h" +const static char *TAG = "esp_apptrace"; + +#if ESP_APPTRACE_PRINT_LOCK != ESP_APPTRACE_PRINT_LOCK_NONE +#define ESP_APPTRACE_LOG( format, ... ) \ + do { \ + esp_apptrace_log_lock(); \ + ets_printf(format, ##__VA_ARGS__); \ + esp_apptrace_log_unlock(); \ + } while(0) +#else +#define ESP_APPTRACE_LOG( format, ... ) \ + do { \ + ets_printf(format, ##__VA_ARGS__); \ + } while(0) +#endif + +#define ESP_APPTRACE_LOG_LEV( _L_, level, format, ... ) \ + do { \ + if (LOG_LOCAL_LEVEL >= level) { \ + ESP_APPTRACE_LOG(LOG_FORMAT(_L_, format), esp_log_early_timestamp(), TAG, ##__VA_ARGS__); \ + } \ + } while(0) + +#define ESP_APPTRACE_LOGE( format, ... ) ESP_APPTRACE_LOG_LEV(E, ESP_LOG_ERROR, format, ##__VA_ARGS__) +#define ESP_APPTRACE_LOGW( format, ... ) ESP_APPTRACE_LOG_LEV(W, ESP_LOG_WARN, format, ##__VA_ARGS__) +#define ESP_APPTRACE_LOGI( format, ... ) ESP_APPTRACE_LOG_LEV(I, ESP_LOG_INFO, format, ##__VA_ARGS__) +#define ESP_APPTRACE_LOGD( format, ... ) ESP_APPTRACE_LOG_LEV(D, ESP_LOG_DEBUG, format, ##__VA_ARGS__) +#define ESP_APPTRACE_LOGV( format, ... ) ESP_APPTRACE_LOG_LEV(V, ESP_LOG_VERBOSE, format, ##__VA_ARGS__) +#define ESP_APPTRACE_LOGO( format, ... ) ESP_APPTRACE_LOG_LEV(E, ESP_LOG_NONE, format, ##__VA_ARGS__) + +#define ESP_APPTRACE_CPUTICKS2US(_t_) ((_t_)/(XT_CLOCK_FREQ/1000000)) + +// TODO: move these (and same definitions in trax.c to dport_reg.h) +#define TRACEMEM_MUX_PROBLK0_APPBLK1 0 +#define TRACEMEM_MUX_BLK0_ONLY 1 +#define TRACEMEM_MUX_BLK1_ONLY 2 +#define TRACEMEM_MUX_PROBLK1_APPBLK0 3 + +// TRAX is disabled, so we use its registers for our own purposes +// | 31..XXXXXX..24 | 23 .(host_connect). 23| 22..(block_id)..15 | 14..(block_len)..0 | +#define ESP_APPTRACE_TRAX_CTRL_REG ERI_TRAX_DELAYCNT +#define ESP_APPTRACE_TRAX_STAT_REG ERI_TRAX_TRIGGERPC + +#define ESP_APPTRACE_TRAX_BLOCK_LEN_MSK 0x7FFFUL +#define ESP_APPTRACE_TRAX_BLOCK_LEN(_l_) ((_l_) & ESP_APPTRACE_TRAX_BLOCK_LEN_MSK) +#define ESP_APPTRACE_TRAX_BLOCK_LEN_GET(_v_) ((_v_) & ESP_APPTRACE_TRAX_BLOCK_LEN_MSK) +#define ESP_APPTRACE_TRAX_BLOCK_ID_MSK 0xFFUL +#define ESP_APPTRACE_TRAX_BLOCK_ID(_id_) (((_id_) & ESP_APPTRACE_TRAX_BLOCK_ID_MSK) << 15) +#define ESP_APPTRACE_TRAX_BLOCK_ID_GET(_v_) (((_v_) >> 15) & ESP_APPTRACE_TRAX_BLOCK_ID_MSK) +#define ESP_APPTRACE_TRAX_HOST_CONNECT (1 << 23) + +static volatile uint8_t *s_trax_blocks[] = { + (volatile uint8_t *) 0x3FFFC000, + (volatile uint8_t *) 0x3FFF8000 +}; + +#define ESP_APPTRACE_TRAX_BLOCKS_NUM (sizeof(s_trax_blocks)/sizeof(s_trax_blocks[0])) + +//#define ESP_APPTRACE_TRAX_BUFFER_SIZE (ESP_APPTRACE_TRAX_BLOCK_SIZE/4) + +#define ESP_APPTRACE_TRAX_INBLOCK_START 0//(ESP_APPTRACE_TRAX_BLOCK_ID_MSK - 4) + + +#define ESP_APPTRACE_TRAX_INBLOCK_MARKER_PTR_GET() (&s_trace_buf.trax.state.markers[s_trace_buf.trax.state.in_block % 2]) +#define ESP_APPTRACE_TRAX_INBLOCK_GET() (&s_trace_buf.trax.blocks[s_trace_buf.trax.state.in_block % 2]) + +#if ESP_APPTRACE_DEBUG_STATS_ENABLE == 1 +/** keeps info about apptrace API (write/get buffer) caller and internal module's data related to that call + * NOTE: used for module debug purposes, currently this functionality is partially broken, + * but can be useful in future + */ +typedef struct { + uint32_t hnd; // task/ISR handle + uint32_t ts; // timestamp + uint32_t stamp; // test (user) trace buffer stamp + uint32_t in_block; // TRAX input block ID + uint32_t eri_len[2]; // contents of ERI control register upon entry to / exit from API routine + uint32_t wr_err; // number of trace write errors +} esp_trace_buffer_wr_hitem_t; + +/** apptrace API calls history. History is organized as ring buffer*/ +typedef struct { + uint32_t hist_rd; // the first history entry index + uint32_t hist_wr; // the last history entry index + esp_trace_buffer_wr_hitem_t hist[ESP_APPTRACE_BUF_HISTORY_DEPTH]; // history data +} esp_trace_buffer_wr_stats_t; + +/** trace module stats */ +typedef struct { + esp_trace_buffer_wr_stats_t wr; +} esp_trace_buffer_stats_t; +#endif + +/** Trace data header. Every user data chunk is prepended with this header. + * User allocates block with esp_apptrace_buffer_get and then fills it with data, + * in multithreading environment it can happen that tasks gets buffer and then gets interrupted, + * so it is possible that user data are incomplete when TRAX memory block is exposed to the host. + * In this case host SW will see that wr_sz < block_sz and will report error. + */ +typedef struct { + uint16_t block_sz; // size of allocated block for user data + uint16_t wr_sz; // size of actually written data +} esp_tracedata_hdr_t; + +/** TRAX HW transport state */ +typedef struct { + uint32_t in_block; // input block ID + uint32_t markers[ESP_APPTRACE_TRAX_BLOCKS_NUM]; // block filling level markers +#if ESP_APPTRACE_DEBUG_STATS_ENABLE == 1 + esp_trace_buffer_stats_t stats; // stats +#endif +} esp_apptrace_trax_state_t; + +/** memory block parameters */ +typedef struct { + uint8_t *start; // start address + uint32_t sz; // size +} esp_apptrace_mem_block_t; + +/** TRAX HW transport data */ +typedef struct { + volatile esp_apptrace_trax_state_t state; // state + esp_apptrace_mem_block_t blocks[ESP_APPTRACE_TRAX_BLOCKS_NUM]; // memory blocks +} esp_apptrace_trax_data_t; + +/** tracing module synchronization lock */ +typedef struct { + volatile unsigned int irq_stat; // local (on 1 CPU) IRQ state + portMUX_TYPE portmux; // mux for synchronization +} esp_apptrace_lock_t; + +#define ESP_APPTRACE_MUX_GET(_m_) (&(_m_)->portmux) + +/** tracing module internal data */ +typedef struct { +#if ESP_APPTRACE_USE_LOCK_SEM == 1 + SemaphoreHandle_t lock; +#else + esp_apptrace_lock_t lock; // sync lock +#endif + uint8_t inited; // module initialization state flag + esp_apptrace_trax_data_t trax; // TRAX HW transport data +} esp_apptrace_buffer_t; + +/** waiting timeout data */ +typedef struct { + uint32_t start; // waiting start (in ticks) + uint32_t tmo; // timeout (in us) +} esp_apptrace_tmo_t; + +static esp_apptrace_buffer_t s_trace_buf; + +#if ESP_APPTRACE_PRINT_LOCK == ESP_APPTRACE_PRINT_LOCK_SEM +static SemaphoreHandle_t s_log_lock; +#elif ESP_APPTRACE_PRINT_LOCK == ESP_APPTRACE_PRINT_LOCK_MUX +static esp_apptrace_lock_t s_log_lock; +#endif + +static inline void esp_apptrace_tmo_init(esp_apptrace_tmo_t *tmo, uint32_t user_tmo) +{ + tmo->start = xthal_get_ccount(); + tmo->tmo = user_tmo; +} + +static esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo) +{ + unsigned cur, elapsed; + + if (tmo->tmo != ESP_APPTRACE_TMO_INFINITE) { + cur = xthal_get_ccount(); + if (tmo->start <= cur) { + elapsed = cur - tmo->start; + } else { + elapsed = 0xFFFFFFFF - tmo->start + cur; + } + if (ESP_APPTRACE_CPUTICKS2US(elapsed) >= tmo->tmo) { + return ESP_ERR_TIMEOUT; + } + } + return ESP_OK; +} + +#if ESP_APPTRACE_PRINT_LOCK == ESP_APPTRACE_PRINT_LOCK_MUX || ESP_APPTRACE_USE_LOCK_SEM == 0 +static inline void esp_apptrace_mux_init(esp_apptrace_lock_t *mux) +{ + ESP_APPTRACE_MUX_GET(mux)->mux = portMUX_FREE_VAL; + mux->irq_stat = 0; +} + +static esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *mux, uint32_t tmo) +{ + uint32_t res = ~portMUX_FREE_VAL; + esp_apptrace_tmo_t sleeping_tmo; + + esp_apptrace_tmo_init(&sleeping_tmo, tmo); + while (1) { + res = (xPortGetCoreID() << portMUX_VAL_SHIFT) | portMUX_MAGIC_VAL; + // first disable IRQs on this CPU, this will prevent current task from been + // preempted by higher prio tasks, otherwise deadlock can happen: + // when lower prio task took mux and then preempted by higher prio one which also tries to + // get mux with INFINITE timeout + unsigned int irq_stat = portENTER_CRITICAL_NESTED(); + // Now try to lock mux + uxPortCompareSet(&ESP_APPTRACE_MUX_GET(mux)->mux, portMUX_FREE_VAL, &res); + if (res == portMUX_FREE_VAL) { + // do not enable IRQs, we will held them disabled until mux is unlocked + // we do not need to flush cache region for mux->irq_stat because it is used + // to hold and restore IRQ state only for CPU which took mux, other CPUs will not use this value + mux->irq_stat = irq_stat; + break; + } + // if mux is locked by other task/ISR enable IRQs and let other guys work + portEXIT_CRITICAL_NESTED(irq_stat); + + if (!xPortInIsrContext()) { + portYIELD(); + } + + int err = esp_apptrace_tmo_check(&sleeping_tmo); + if (err != ESP_OK) { + return err; + } + } + + return ESP_OK; +} + +esp_err_t esp_apptrace_mux_give(esp_apptrace_lock_t *mux) +{ + esp_err_t ret = ESP_OK; + uint32_t res = 0; + unsigned int irq_stat; + + res = portMUX_FREE_VAL; + + // first of all save a copy of IRQ status for this locker because uxPortCompareSet will unlock mux and tasks/ISRs + // from other core can overwrite mux->irq_stat + irq_stat = mux->irq_stat; + uxPortCompareSet(&ESP_APPTRACE_MUX_GET(mux)->mux, (xPortGetCoreID() << portMUX_VAL_SHIFT) | portMUX_MAGIC_VAL, &res); + // enable local interrupts + portEXIT_CRITICAL_NESTED(irq_stat); + + if ( ((res & portMUX_VAL_MASK) >> portMUX_VAL_SHIFT) == xPortGetCoreID() ) { + // nothing to do + } else if ( res == portMUX_FREE_VAL ) { + ret = ESP_FAIL; // should never get here + } else { + ret = ESP_FAIL; // should never get here + } + return ret; +} +#endif + +static inline esp_err_t esp_apptrace_log_init() +{ +#if ESP_APPTRACE_PRINT_LOCK == ESP_APPTRACE_PRINT_LOCK_SEM + s_log_lock = xSemaphoreCreateBinary(); + if (!s_log_lock) { + ets_printf("%s: Failed to create print lock sem!", TAG); + return ESP_FAIL; + } + xSemaphoreGive(s_log_lock); +#elif ESP_APPTRACE_PRINT_LOCK == ESP_APPTRACE_PRINT_LOCK_MUX + esp_apptrace_mux_init(&s_log_lock); +#endif + return ESP_OK; +} + +static inline void esp_apptrace_log_cleanup() +{ +#if ESP_APPTRACE_PRINT_LOCK == ESP_APPTRACE_PRINT_LOCK_SEM + vSemaphoreDelete(s_log_lock); +#endif +} + +static inline int esp_apptrace_log_lock() +{ +#if ESP_APPTRACE_PRINT_LOCK == ESP_APPTRACE_PRINT_LOCK_SEM + BaseType_t ret; + if (xPortInIsrContext()) { + ret = xSemaphoreTakeFromISR(s_print_lock, NULL); + } else { + ret = xSemaphoreTake(s_print_lock, portMAX_DELAY); + } + return ret; +#elif ESP_APPTRACE_PRINT_LOCK == ESP_APPTRACE_PRINT_LOCK_MUX + int ret = esp_apptrace_lock_take(&s_log_lock, ESP_APPTRACE_TMO_INFINITE); + return ret; +#endif + return 0; +} + +static inline void esp_apptrace_log_unlock() +{ +#if ESP_APPTRACE_PRINT_LOCK == ESP_APPTRACE_PRINT_LOCK_SEM + if (xPortInIsrContext()) { + xSemaphoreGiveFromISR(s_log_lock, NULL); + } else { + xSemaphoreGive(s_log_lock); + } +#elif ESP_APPTRACE_PRINT_LOCK == ESP_APPTRACE_PRINT_LOCK_MUX + esp_apptrace_mux_give(&s_log_lock); +#endif +} + +esp_err_t esp_apptrace_lock_init() +{ +#if ESP_APPTRACE_USE_LOCK_SEM == 1 + s_trace_buf.lock = xSemaphoreCreateBinary(); + if (!s_trace_buf.lock) { + ESP_APPTRACE_LOGE("Failed to create lock!"); + return ESP_FAIL; + } + xSemaphoreGive(s_trace_buf.lock); +#else + esp_apptrace_mux_init(&s_trace_buf.lock); +#endif + return ESP_OK; +} + +esp_err_t esp_apptrace_lock_cleanup() +{ +#if ESP_APPTRACE_USE_LOCK_SEM == 1 + vSemaphoreDelete(s_trace_buf.lock); +#endif + return ESP_OK; +} + +esp_err_t esp_apptrace_lock(uint32_t *tmo) +{ + unsigned cur, elapsed, start = xthal_get_ccount(); + +#if ESP_APPTRACE_USE_LOCK_SEM == 1 + BaseType_t ret; + if (xPortInIsrContext()) { + ret = xSemaphoreTakeFromISR(s_trace_buf.lock, NULL); + } else { + ret = xSemaphoreTake(s_trace_buf.lock, portTICK_PERIOD_MS * (*tmo) / 1000); + } + if (ret != pdTRUE) { + return ESP_FAIL; + } +#else + esp_err_t ret = esp_apptrace_lock_take(&s_trace_buf.lock, *tmo); + if (ret != ESP_OK) { + return ESP_FAIL; + } +#endif + // decrease tmo by actual waiting time + cur = xthal_get_ccount(); + if (start <= cur) { + elapsed = cur - start; + } else { + elapsed = ULONG_MAX - start + cur; + } + if (ESP_APPTRACE_CPUTICKS2US(elapsed) > *tmo) { + *tmo = 0; + } else { + *tmo -= ESP_APPTRACE_CPUTICKS2US(elapsed); + } + + return ESP_OK; +} + +esp_err_t esp_apptrace_unlock() +{ + esp_err_t ret = ESP_OK; +#if ESP_APPTRACE_USE_LOCK_SEM == 1 + if (xPortInIsrContext()) { + xSemaphoreGiveFromISR(s_trace_buf.lock, NULL); + } else { + xSemaphoreGive(s_trace_buf.lock); + } +#else + ret = esp_apptrace_mux_give(&s_trace_buf.lock); +#endif + return ret; +} + +#if CONFIG_ESP32_APPTRACE_DEST_TRAX +static void esp_apptrace_trax_init() +{ + // Stop trace, if any (on the current CPU) + eri_write(ERI_TRAX_TRAXCTRL, TRAXCTRL_TRSTP); + eri_write(ERI_TRAX_TRAXCTRL, TRAXCTRL_TMEN); + eri_write(ESP_APPTRACE_TRAX_CTRL_REG, ESP_APPTRACE_TRAX_BLOCK_ID(ESP_APPTRACE_TRAX_INBLOCK_START)); + eri_write(ESP_APPTRACE_TRAX_STAT_REG, 0); + + ESP_APPTRACE_LOGI("Initialized TRAX on CPU%d", xPortGetCoreID()); +} + +// assumed to be protected by caller from multi-core/thread access +static esp_err_t esp_apptrace_trax_block_switch() +{ + int prev_block_num = s_trace_buf.trax.state.in_block % 2; + int new_block_num = prev_block_num ? (0) : (1); + int res = ESP_OK; + extern uint32_t __esp_apptrace_trax_eri_updated; + + // indicate to host that we are about to update. + // this is used only to place CPU into streaming mode at tracing startup + // before starting streaming host can halt us after we read ESP_APPTRACE_TRAX_CTRL_REG and before we updated it + // HACK: in this case host will set breakpoint just after ESP_APPTRACE_TRAX_CTRL_REG update, + // here we set address to set bp at + // enter ERI update critical section + eri_write(ESP_APPTRACE_TRAX_STAT_REG, (uint32_t)&__esp_apptrace_trax_eri_updated); + + uint32_t ctrl_reg = eri_read(ESP_APPTRACE_TRAX_CTRL_REG); +#if ESP_APPTRACE_DEBUG_STATS_ENABLE == 1 + if (s_trace_buf.state.stats.wr.hist_wr < ESP_APPTRACE_BUF_HISTORY_DEPTH) { + esp_trace_buffer_wr_hitem_t *hi = (esp_trace_buffer_wr_hitem_t *)&s_trace_buf.state.stats.wr.hist[s_trace_buf.state.stats.wr.hist_wr - 1]; + hi->eri_len[1] = ctrl_reg; + } +#endif + uint32_t host_connected = ESP_APPTRACE_TRAX_HOST_CONNECT & ctrl_reg; + if (host_connected) { + uint32_t acked_block = ESP_APPTRACE_TRAX_BLOCK_ID_GET(ctrl_reg); + uint32_t host_to_read = ESP_APPTRACE_TRAX_BLOCK_LEN_GET(ctrl_reg); + if (host_to_read != 0 || acked_block != (s_trace_buf.trax.state.in_block & ESP_APPTRACE_TRAX_BLOCK_ID_MSK)) { + // ESP_APPTRACE_LOGE("HC[%d]: Can not switch %x %d %x %x/%lx", xPortGetCoreID(), ctrl_reg, host_to_read, acked_block, + // s_trace_buf.trax.state.in_block & ESP_APPTRACE_TRAX_BLOCK_ID_MSK, s_trace_buf.trax.state.in_block); + res = ESP_ERR_NO_MEM; + goto _on_func_exit; + } + } + s_trace_buf.trax.state.markers[new_block_num] = 0; + // switch to new block + s_trace_buf.trax.state.in_block++; + + WRITE_PERI_REG(DPORT_TRACEMEM_MUX_MODE_REG, new_block_num ? TRACEMEM_MUX_BLK0_ONLY : TRACEMEM_MUX_BLK1_ONLY); + eri_write(ESP_APPTRACE_TRAX_CTRL_REG, ESP_APPTRACE_TRAX_BLOCK_ID(s_trace_buf.trax.state.in_block) | + host_connected | ESP_APPTRACE_TRAX_BLOCK_LEN(s_trace_buf.trax.state.markers[prev_block_num])); + +_on_func_exit: + // exit ERI update critical section + eri_write(ESP_APPTRACE_TRAX_STAT_REG, 0x0); + asm volatile ( + " .global __esp_apptrace_trax_eri_updated\n" + "__esp_apptrace_trax_eri_updated:\n"); // host will set bp here to resolve collision at streaming start + return res; +} + +static esp_err_t esp_apptrace_trax_block_switch_waitus(uint32_t tmo) +{ + int res; + esp_apptrace_tmo_t sleeping_tmo; + + esp_apptrace_tmo_init(&sleeping_tmo, tmo); + + while ((res = esp_apptrace_trax_block_switch()) != ESP_OK) { + res = esp_apptrace_tmo_check(&sleeping_tmo); + if (res != ESP_OK) { + break; + } + } + return res; +} + +static uint8_t *esp_apptrace_trax_get_buffer(size_t size, uint32_t *tmo) +{ + uint8_t *buf_ptr = NULL; + volatile uint32_t *cur_block_marker; + esp_apptrace_mem_block_t *cur_block; + + int res = esp_apptrace_lock(tmo); + if (res != ESP_OK) { + return NULL; + } + +#if ESP_APPTRACE_DEBUG_STATS_ENABLE == 1 + esp_trace_buffer_wr_hitem_t *hi = NULL; + if (s_trace_buf.state.stats.wr.hist_wr < ESP_APPTRACE_BUF_HISTORY_DEPTH) { + hi = (esp_trace_buffer_wr_hitem_t *)&s_trace_buf.state.stats.wr.hist[s_trace_buf.state.stats.wr.hist_wr++]; + hi->hnd = *(uint32_t *)(buf + 0); + hi->ts = *(uint32_t *)(buf + sizeof(uint32_t)); + hi->stamp = *(buf + 2 * sizeof(uint32_t)); + hi->in_block = s_trace_buf.state.in_block; + hi->wr_err = 0; + hi->eri_len[0] = eri_read(ESP_APPTRACE_TRAX_CTRL_REG); + if (s_trace_buf.state.stats.wr.hist_wr == ESP_APPTRACE_BUF_HISTORY_DEPTH) { + s_trace_buf.state.stats.wr.hist_wr = 0; + } + if (s_trace_buf.state.stats.wr.hist_wr == s_trace_buf.state.stats.wr.hist_rd) { + s_trace_buf.state.stats.wr.hist_rd++; + if (s_trace_buf.state.stats.wr.hist_rd == ESP_APPTRACE_BUF_HISTORY_DEPTH) { + s_trace_buf.state.stats.wr.hist_rd = 0; + } + } + } +#endif + + cur_block_marker = ESP_APPTRACE_TRAX_INBLOCK_MARKER_PTR_GET(); + cur_block = ESP_APPTRACE_TRAX_INBLOCK_GET(); + + if (*cur_block_marker + size + sizeof(esp_tracedata_hdr_t) >= cur_block->sz) { + // flush data, we can not unlock apptrace until we have buffer for all user data + // otherwise other tasks/ISRs can get control and write their data between chunks of this data + res = esp_apptrace_trax_block_switch_waitus(/*size + sizeof(esp_tracedata_hdr_t),*/*tmo); + if (res != ESP_OK) { + if (esp_apptrace_unlock() != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to unlock apptrace data!"); + // there is a bug, should never get here + } + return NULL; + } + // we switched to new block, update TRAX block pointers + cur_block_marker = ESP_APPTRACE_TRAX_INBLOCK_MARKER_PTR_GET(); + cur_block = ESP_APPTRACE_TRAX_INBLOCK_GET(); + } + + buf_ptr = cur_block->start + *cur_block_marker; + ((esp_tracedata_hdr_t *)buf_ptr)->block_sz = size; + ((esp_tracedata_hdr_t *)buf_ptr)->wr_sz = 0; + + *cur_block_marker += size + sizeof(esp_tracedata_hdr_t); + + // now we can safely unlock apptrace to allow other tasks/ISRs to get other buffers and write their data + if (esp_apptrace_unlock() != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to unlock apptrace data!"); + // there is a bug, should never get here + } + + return buf_ptr + sizeof(esp_tracedata_hdr_t); +} + +static esp_err_t esp_apptrace_trax_put_buffer(uint8_t *ptr, uint32_t *tmo) +{ + int res = ESP_OK; + esp_tracedata_hdr_t *hdr = (esp_tracedata_hdr_t *)(ptr - sizeof(esp_tracedata_hdr_t)); + + // update written size + hdr->wr_sz = hdr->block_sz; + + // TODO: mark block as busy in order not to re-use it for other tracing calls until it is completely written + // TODO: avoid potential situation when all memory is consumed by low prio tasks which can not complete writing due to + // higher prio tasks and the latter can not allocate buffers at all + // this is abnormal situation can be detected on host which will receive only uncompleted buffers + // workaround: use own memcpy which will kick-off dead tracing calls + + return res; +} + +static esp_err_t esp_apptrace_trax_flush(uint32_t min_sz, uint32_t tmo) +{ + volatile uint32_t *in_block_marker; + int res = ESP_OK; + + in_block_marker = ESP_APPTRACE_TRAX_INBLOCK_MARKER_PTR_GET(); + if (*in_block_marker > min_sz) { + ESP_APPTRACE_LOGD("Wait until block switch for %u us", tmo); + res = esp_apptrace_trax_block_switch_waitus(/*0 query any size,*/tmo); + if (res != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to switch to another block"); + return res; + } + ESP_APPTRACE_LOGD("Flushed last block %u bytes", *in_block_marker); + *in_block_marker = 0; + } + + return res; +} + +static esp_err_t esp_apptrace_trax_dest_init() +{ + for (int i = 0; i < ESP_APPTRACE_TRAX_BLOCKS_NUM; i++) { + s_trace_buf.trax.blocks[i].start = (uint8_t *)s_trax_blocks[i]; + s_trace_buf.trax.blocks[i].sz = ESP_APPTRACE_TRAX_BLOCK_SIZE; + s_trace_buf.trax.state.markers[i] = 0; + } + s_trace_buf.trax.state.in_block = ESP_APPTRACE_TRAX_INBLOCK_START; + + WRITE_PERI_REG(DPORT_PRO_TRACEMEM_ENA_REG, DPORT_PRO_TRACEMEM_ENA_M); +#if CONFIG_FREERTOS_UNICORE == 0 + WRITE_PERI_REG(DPORT_APP_TRACEMEM_ENA_REG, DPORT_APP_TRACEMEM_ENA_M); +#endif + // Expose block 1 to host, block 0 is current trace input buffer + WRITE_PERI_REG(DPORT_TRACEMEM_MUX_MODE_REG, TRACEMEM_MUX_BLK1_ONLY); + + return ESP_OK; +} +#endif + +esp_err_t esp_apptrace_init() +{ + int res; + + if (!s_trace_buf.inited) { + res = esp_apptrace_log_init(); + if (res != ESP_OK) { + ets_printf("%s: Failed to init log lock (%d)!", TAG, res); + return res; + } + //memset(&s_trace_buf, 0, sizeof(s_trace_buf)); + res = esp_apptrace_lock_init(&s_trace_buf.lock); + if (res != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to init log lock (%d)!", res); + esp_apptrace_log_cleanup(); + return res; + } +#if CONFIG_ESP32_APPTRACE_DEST_TRAX + res = esp_apptrace_trax_dest_init(); + if (res != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to init TRAX dest data (%d)!", res); + esp_apptrace_lock_cleanup(); + esp_apptrace_log_cleanup(); + return res; + } +#endif + } + +#if CONFIG_ESP32_APPTRACE_DEST_TRAX + // init TRAX on this CPU + esp_apptrace_trax_init(); +#endif + + s_trace_buf.inited |= 1 << xPortGetCoreID(); // global and this CPU-specific data are inited + + return ESP_OK; +} + +esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, void *data, size_t size, uint32_t user_tmo) +{ + uint8_t *ptr = NULL; + uint32_t tmo = user_tmo; + //TODO: use ptr to HW transport iface struct + uint8_t *(*apptrace_get_buffer)(size_t, uint32_t *); + esp_err_t (*apptrace_put_buffer)(uint8_t *, uint32_t *); + + if (dest == ESP_APPTRACE_DEST_TRAX) { +#if CONFIG_ESP32_APPTRACE_DEST_TRAX + apptrace_get_buffer = esp_apptrace_trax_get_buffer; + apptrace_put_buffer = esp_apptrace_trax_put_buffer; +#else + ESP_APPTRACE_LOGE("Application tracing via TRAX is disabled in menuconfig!"); + return ESP_ERR_NOT_SUPPORTED; +#endif + } else { + ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!"); + return ESP_ERR_NOT_SUPPORTED; + } + + ptr = apptrace_get_buffer(size, &tmo); + if (ptr == NULL) { + //ESP_APPTRACE_LOGE("Failed to get buffer!"); + return ESP_ERR_NO_MEM; + } + + // actually can be suspended here by higher prio tasks/ISRs + //TODO: use own memcpy with dead trace calls kick-off algo, and tmo expiration check + memcpy(ptr, data, size); + + // now indicate that this buffer is ready to be sent off to host + return apptrace_put_buffer(ptr, &tmo); +} + +int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t user_tmo, const char *fmt, va_list ap) +{ + uint16_t nargs = 0; + uint8_t *pout, *p = (uint8_t *)fmt; + uint32_t tmo = user_tmo; + //TODO: use ptr to HW transport iface struct + uint8_t *(*apptrace_get_buffer)(size_t, uint32_t *); + esp_err_t (*apptrace_put_buffer)(uint8_t *, uint32_t *); + + if (dest == ESP_APPTRACE_DEST_TRAX) { +#if CONFIG_ESP32_APPTRACE_DEST_TRAX + apptrace_get_buffer = esp_apptrace_trax_get_buffer; + apptrace_put_buffer = esp_apptrace_trax_put_buffer; +#else + ESP_APPTRACE_LOGE("Application tracing via TRAX is disabled in menuconfig!"); + return ESP_ERR_NOT_SUPPORTED; +#endif + } else { + ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!"); + return ESP_ERR_NOT_SUPPORTED; + } + + // ESP_APPTRACE_LOGI("fmt %x", fmt); + while ((p = (uint8_t *)strchr((char *)p, '%')) && nargs < ESP_APPTRACE_MAX_VPRINTF_ARGS) { + p++; + if (*p != '%' && *p != 0) { + nargs++; + } + } + // ESP_APPTRACE_LOGI("nargs = %d", nargs); + if (p) { + ESP_APPTRACE_LOGE("Failed to store all printf args!"); + } + + pout = apptrace_get_buffer(1 + sizeof(char *) + nargs * sizeof(uint32_t), &tmo); + if (pout == NULL) { + ESP_APPTRACE_LOGE("Failed to get buffer!"); + return -1; + } + p = pout; + *pout = nargs; + pout++; + *(const char **)pout = fmt; + pout += sizeof(char *); + while (nargs-- > 0) { + uint32_t arg = va_arg(ap, uint32_t); + *(uint32_t *)pout = arg; + pout += sizeof(uint32_t); + // ESP_APPTRACE_LOGI("arg %x", arg); + } + + int ret = apptrace_put_buffer(p, &tmo); + if (ret != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to put printf buf (%d)!", ret); + return -1; + } + + return (pout - p); +} + +int esp_apptrace_vprintf(const char *fmt, va_list ap) +{ + return esp_apptrace_vprintf_to(ESP_APPTRACE_DEST_TRAX, /*ESP_APPTRACE_TMO_INFINITE*/0, fmt, ap); +} + +uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, size_t size, uint32_t user_tmo) +{ + uint32_t tmo = user_tmo; + //TODO: use ptr to HW transport iface struct + uint8_t *(*apptrace_get_buffer)(size_t, uint32_t *); + + if (dest == ESP_APPTRACE_DEST_TRAX) { +#if CONFIG_ESP32_APPTRACE_DEST_TRAX + apptrace_get_buffer = esp_apptrace_trax_get_buffer; +#else + ESP_APPTRACE_LOGE("Application tracing via TRAX is disabled in menuconfig!"); + return NULL; +#endif + } else { + ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!"); + return NULL; + } + + return apptrace_get_buffer(size, &tmo); +} + +esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t user_tmo) +{ + uint32_t tmo = user_tmo; + //TODO: use ptr to HW transport iface struct + esp_err_t (*apptrace_put_buffer)(uint8_t *, uint32_t *); + + if (dest == ESP_APPTRACE_DEST_TRAX) { +#if CONFIG_ESP32_APPTRACE_DEST_TRAX + apptrace_put_buffer = esp_apptrace_trax_put_buffer; +#else + ESP_APPTRACE_LOGE("Application tracing via TRAX is disabled in menuconfig!"); + return ESP_ERR_NOT_SUPPORTED; +#endif + } else { + ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!"); + return ESP_ERR_NOT_SUPPORTED; + } + + return apptrace_put_buffer(ptr, &tmo); +} + +esp_err_t esp_apptrace_flush_nolock(esp_apptrace_dest_t dest, uint32_t min_sz, uint32_t tmo) +{ + //TODO: use ptr to HW transport iface struct + esp_err_t (*apptrace_flush)(uint32_t, uint32_t); + + if (dest == ESP_APPTRACE_DEST_TRAX) { +#if CONFIG_ESP32_APPTRACE_DEST_TRAX + apptrace_flush = esp_apptrace_trax_flush; +#else + ESP_APPTRACE_LOGE("Application tracing via TRAX is disabled in menuconfig!"); + return ESP_ERR_NOT_SUPPORTED; +#endif + } else { + ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!"); + return ESP_ERR_NOT_SUPPORTED; + } + + return apptrace_flush(min_sz, tmo); +} + +esp_err_t esp_apptrace_flush(esp_apptrace_dest_t dest, uint32_t tmo) +{ + int res; + + res = esp_apptrace_lock(&tmo); + if (res != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to lock apptrace data (%d)!", res); + return res; + } + + res = esp_apptrace_flush_nolock(dest, 0, tmo); + if (res != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to fluch apptrace data (%d)!", res); + } + + if (esp_apptrace_unlock() != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to unlock apptrace data (%d)!", res); + } + + return res; +} + +#if ESP_APPTRACE_DEBUG_STATS_ENABLE == 1 +void esp_apptrace_print_stats() +{ + uint32_t i; + uint32_t tmo = ESP_APPTRACE_TMO_INFINITE; + + esp_apptrace_lock(&tmo); + + for (i = s_trace_buf.state.stats.wr.hist_rd; (i < s_trace_buf.state.stats.wr.hist_wr) && (i < ESP_APPTRACE_BUF_HISTORY_DEPTH); i++) { + esp_trace_buffer_wr_hitem_t *hi = (esp_trace_buffer_wr_hitem_t *)&s_trace_buf.state.stats.wr.hist[i]; + ESP_APPTRACE_LOGO("hist[%u] = {%x, %x}", i, hi->hnd, hi->ts); + } + if (i == ESP_APPTRACE_BUF_HISTORY_DEPTH) { + for (i = 0; i < s_trace_buf.state.stats.wr.hist_wr; i++) { + esp_trace_buffer_wr_hitem_t *hi = (esp_trace_buffer_wr_hitem_t *)&s_trace_buf.state.stats.wr.hist[i]; + ESP_APPTRACE_LOGO("hist[%u] = {%x, %x}", i, hi->hnd, hi->ts); + } + } + + esp_apptrace_unlock(); +} +#endif +#endif diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index c3ef142c6..9a088bb7b 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -59,6 +59,7 @@ #include "esp_coexist.h" #include "esp_panic.h" #include "esp_core_dump.h" +#include "esp_app_trace.h" #include "trax.h" #define STRINGIFY(s) STRINGIFY2(s) @@ -193,8 +194,8 @@ void start_cpu0_default(void) { esp_setup_syscall_table(); //Enable trace memory and immediately start trace. -#if CONFIG_MEMMAP_TRACEMEM -#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS +#if CONFIG_ESP32_TRAX +#if CONFIG_ESP32_TRAX_TWOBANKS trax_enable(TRAX_ENA_PRO_APP); #else trax_enable(TRAX_ENA_PRO); @@ -221,6 +222,12 @@ void start_cpu0_default(void) _GLOBAL_REENT->_stdin = (FILE*) &__sf_fake_stdin; _GLOBAL_REENT->_stdout = (FILE*) &__sf_fake_stdout; _GLOBAL_REENT->_stderr = (FILE*) &__sf_fake_stderr; +#endif +#if CONFIG_ESP32_APPTRACE_ENABLE + esp_err_t err = esp_apptrace_init(); + if (err != ESP_OK) { + ESP_EARLY_LOGE(TAG, "Failed to init apptrace module on CPU0 (%d)!", err); + } #endif do_global_ctors(); #if CONFIG_INT_WDT @@ -250,8 +257,14 @@ void start_cpu0_default(void) #if !CONFIG_FREERTOS_UNICORE void start_cpu1_default(void) { -#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS +#if CONFIG_ESP32_TRAX_TWOBANKS trax_start_trace(TRAX_DOWNCOUNT_WORDS); +#endif +#if CONFIG_ESP32_APPTRACE_ENABLE + esp_err_t err = esp_apptrace_init(); + if (err != ESP_OK) { + ESP_EARLY_LOGE(TAG, "Failed to init apptrace module on CPU1 (%d)!", err); + } #endif // Wait for FreeRTOS initialization to finish on PRO CPU while (port_xSchedulerRunning[0] == 0) { diff --git a/components/esp32/include/esp_app_trace.h b/components/esp32/include/esp_app_trace.h new file mode 100644 index 000000000..bd33e589d --- /dev/null +++ b/components/esp32/include/esp_app_trace.h @@ -0,0 +1,123 @@ +// Copyright 2017 Espressif Systems (Shanghai) PTE 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. +#ifndef ESP_APP_TRACE_H_ +#define ESP_APP_TRACE_H_ + +#include +#include "esp_err.h" + +// infinite waiting timeout +#define ESP_APPTRACE_TMO_INFINITE ((uint32_t)-1) + +// Trace memory block size +#define ESP_APPTRACE_TRAX_BLOCK_SIZE 0x4000UL + +/** + * Application trace data destinations bits. + */ +typedef enum { + ESP_APPTRACE_DEST_TRAX = 0x1, + ESP_APPTRACE_DEST_UART0 = 0x2, + //ESP_APPTRACE_DEST_UART1 = 0x4, +} esp_apptrace_dest_t; + +/** + * @brief Initializes application tracing module. + * + * @note Should be called before any esp_apptrace_xxx call. + * + * @return ESP_OK on success, otherwise \see esp_err_t + */ +esp_err_t esp_apptrace_init(); + +/** + * @brief Allocates buffer for trace data. + * After data in buffer are ready to be sent off esp_apptrace_buffer_put must be called to indicate it. + * + * @param dest Indicates HW interface to send data. + * @param size Size of data to write to trace buffer. + * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. + * + * @return non-NULL on success, otherwise NULL. + */ +uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, size_t size, uint32_t tmo); + +/** + * @brief Indicates that the data in buffer are ready to be sent off. + * This function is a counterpart of must be preceeded by esp_apptrace_buffer_get. + * + * @param dest Indicates HW interface to send data. Should be identical to the same parameter in call to esp_apptrace_buffer_get. + * @param ptr Address of trace buffer to release. Should be the value returned by call to esp_apptrace_buffer_get. + * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. + * + * @return ESP_OK on success, otherwise \see esp_err_t + */ +esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t tmo); + +/** + * @brief Writes data to trace buffer. + * + * @param dest Indicates HW interface to send data. + * @param data Address of data to write to trace buffer. + * @param size Size of data to write to trace buffer. + * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. + * + * @return ESP_OK on success, otherwise \see esp_err_t + */ +esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, void *data, size_t size, uint32_t tmo); + +/** + * @brief vprintf-like function to sent log messages to host via specified HW interface. + * + * @param dest Indicates HW interface to send data. + * @param fmt Address of format string. + * @param ap List of arguments. + * + * @return Number of bytes written. + */ +int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t user_tmo, const char *fmt, va_list ap); + +/** + * @brief vprintf-like function to sent log messages to host. + * + * @param fmt Address of format string. + * @param ap List of arguments. + * + * @return Number of bytes written. + */ +int esp_apptrace_vprintf(const char *fmt, va_list ap); + +/** + * @brief Flushes remaining data in trace buffer to host. + * + * @param dest Indicates HW interface to flush data on. + * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. + * + * @return ESP_OK on success, otherwise \see esp_err_t + */ +esp_err_t esp_apptrace_flush(esp_apptrace_dest_t dest, uint32_t tmo); + +/** + * @brief Flushes remaining data in trace buffer to host without locking internal data. + This is special version of esp_apptrace_flush which should be called from panic handler. + * + * @param dest Indicates HW interface to flush data on. + * @param min_sz Threshold for flushing data. If current filling level is above this value, data will be flushed. TRAX destinations only. + * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. + * + * @return ESP_OK on success, otherwise \see esp_err_t + */ +esp_err_t esp_apptrace_flush_nolock(esp_apptrace_dest_t dest, uint32_t min_sz, uint32_t tmo); + +#endif diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index 5c1dba68c..67beb35a9 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -86,6 +86,7 @@ SECTIONS *libesp32.a:panic.o(.literal .text .literal.* .text.*) *libesp32.a:core_dump.o(.literal .text .literal.* .text.*) *libesp32.a:heap_alloc_caps.o(.literal .text .literal.* .text.*) + *libesp32.a:app_trace.o(.literal .text .literal.* .text.*) *libphy.a:(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) *libsoc.a:(.literal .text .literal.* .text.*) @@ -116,6 +117,7 @@ SECTIONS KEEP(*(.jcr)) *(.dram1 .dram1.*) *libesp32.a:panic.o(.rodata .rodata.*) + *libesp32.a:app_trace.o(.rodata .rodata.*) _data_end = ABSOLUTE(.); . = ALIGN(4); } >dram0_0_seg diff --git a/components/esp32/panic.c b/components/esp32/panic.c index 08c13f765..8ec362f9c 100644 --- a/components/esp32/panic.c +++ b/components/esp32/panic.c @@ -38,6 +38,7 @@ #include "esp_core_dump.h" #include "esp_spi_flash.h" #include "esp_cache_err_int.h" +#include "esp_app_trace.h" /* Panic handlers; these get called when an unhandled exception occurs or the assembly-level @@ -114,6 +115,9 @@ static bool abort_called; static __attribute__((noreturn)) inline void invoke_abort() { abort_called = true; +#if CONFIG_ESP32_APPTRACE_ENABLE + esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TRAX_BLOCK_SIZE*CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TRAX_THRESH/100, CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO); +#endif while(1) { __asm__ ("break 0,0"); *((int*) 0) = 0; @@ -226,6 +230,9 @@ void panicHandler(XtExcFrame *frame) } if (esp_cpu_in_ocd_debug_mode()) { +#if CONFIG_ESP32_APPTRACE_ENABLE + esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TRAX_BLOCK_SIZE*CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TRAX_THRESH/100, CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO); +#endif setFirstBreakpoint(frame->pc); return; } @@ -248,6 +255,9 @@ void xt_unhandled_exception(XtExcFrame *frame) panicPutStr(" at pc="); panicPutHex(frame->pc); panicPutStr(". Setting bp and returning..\r\n"); +#if CONFIG_ESP32_APPTRACE_ENABLE + esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TRAX_BLOCK_SIZE*CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TRAX_THRESH/100, CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO); +#endif //Stick a hardware breakpoint on the address the handler returns to. This way, the OCD debugger //will kick in exactly at the context the error happened. setFirstBreakpoint(frame->pc); @@ -282,11 +292,10 @@ static void reconfigureAllWdts() TIMERG1.wdt_wprotect = 0; } -#if CONFIG_ESP32_PANIC_GDBSTUB || CONFIG_ESP32_PANIC_PRINT_HALT || CONFIG_ESP32_ENABLE_COREDUMP /* This disables all the watchdogs for when we call the gdbstub. */ -static void disableAllWdts() +static inline void disableAllWdts() { TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; TIMERG0.wdt_config0.en = 0; @@ -296,8 +305,6 @@ static void disableAllWdts() TIMERG1.wdt_wprotect = 0; } -#endif - static void esp_panic_wdt_start() { if (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN)) { @@ -422,6 +429,12 @@ static void commonErrorHandler(XtExcFrame *frame) /* With windowed ABI backtracing is easy, let's do it. */ doBacktrace(frame); +#if CONFIG_ESP32_APPTRACE_ENABLE + disableAllWdts(); + esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TRAX_BLOCK_SIZE*CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TRAX_THRESH/100, CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO); + reconfigureAllWdts(); +#endif + #if CONFIG_ESP32_PANIC_GDBSTUB disableAllWdts(); esp_panic_wdt_stop(); diff --git a/components/esp32/test/test_trace.c b/components/esp32/test/test_trace.c new file mode 100644 index 000000000..48e53adba --- /dev/null +++ b/components/esp32/test/test_trace.c @@ -0,0 +1,817 @@ +#include +#include +#include +#include +#include +#include "unity.h" +#include "driver/timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/task.h" +#if CONFIG_ESP32_APPTRACE_ENABLE == 1 +#include "esp_app_trace.h" + +#define ESP_APPTRACE_TEST_USE_PRINT_LOCK 0 +#define ESP_APPTRACE_TEST_PRN_WRERR_MAX 5 +#define ESP_APPTRACE_TEST_BLOCKS_BEFORE_CRASH 100 +#define ESP_APPTRACE_TEST_BLOCK_SIZE 1024 + +#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE +#include "esp_log.h" +const static char *TAG = "esp_apptrace_test"; + +#if ESP_APPTRACE_TEST_USE_PRINT_LOCK == 1 +#define ESP_APPTRACE_TEST_LOG( format, ... ) \ + do { \ + BaseType_t ret; \ + if (xPortInIsrContext()) \ + ret = xSemaphoreTakeFromISR(s_print_lock, NULL); \ + else \ + ret = xSemaphoreTake(s_print_lock, portMAX_DELAY); \ + if (ret == pdTRUE) { \ + ets_printf(format, ##__VA_ARGS__); \ + if (xPortInIsrContext()) \ + xSemaphoreGiveFromISR(s_print_lock, NULL); \ + else \ + xSemaphoreGive(s_print_lock); \ + } \ + } while(0) +#else +#define ESP_APPTRACE_TEST_LOG( format, ... ) \ + do { \ + ets_printf(format, ##__VA_ARGS__); \ + } while(0) +#endif + +#define ESP_APPTRACE_TEST_LOG_LEVEL( _L_, level, format, ... ) \ + do { \ + if (LOG_LOCAL_LEVEL >= level) { \ + ESP_APPTRACE_TEST_LOG(LOG_FORMAT(_L_, format), esp_log_early_timestamp(), TAG, ##__VA_ARGS__); \ + } \ + } while(0) + +#define ESP_APPTRACE_TEST_LOGE( format, ... ) ESP_APPTRACE_TEST_LOG_LEVEL(E, ESP_LOG_ERROR, format, ##__VA_ARGS__) +#define ESP_APPTRACE_TEST_LOGW( format, ... ) ESP_APPTRACE_TEST_LOG_LEVEL(W, ESP_LOG_WARN, format, ##__VA_ARGS__) +#define ESP_APPTRACE_TEST_LOGI( format, ... ) ESP_APPTRACE_TEST_LOG_LEVEL(I, ESP_LOG_INFO, format, ##__VA_ARGS__) +#define ESP_APPTRACE_TEST_LOGD( format, ... ) ESP_APPTRACE_TEST_LOG_LEVEL(D, ESP_LOG_DEBUG, format, ##__VA_ARGS__) +#define ESP_APPTRACE_TEST_LOGV( format, ... ) ESP_APPTRACE_TEST_LOG_LEVEL(V, ESP_LOG_VERBOSE, format, ##__VA_ARGS__) +#define ESP_APPTRACE_TEST_LOGO( format, ... ) ESP_APPTRACE_TEST_LOG_LEVEL(E, ESP_LOG_NONE, format, ##__VA_ARGS__) + +#define ESP_APPTRACE_TEST_WRITE(_b_, _s_) esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, _b_, _s_, ESP_APPTRACE_TMO_INFINITE) +#define ESP_APPTRACE_TEST_WRITE_FROM_ISR(_b_, _s_) esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, _b_, _s_, 100UL) +#define ESP_APPTRACE_TEST_WRITE_NOWAIT(_b_, _s_) esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, _b_, _s_, 0) + +#define ESP_APPTRACE_TEST_CPUTICKS2US(_t_) ((_t_)/(XT_CLOCK_FREQ/1000000)) + +typedef struct { + uint8_t *buf; + uint32_t buf_sz; + uint8_t mask; + uint32_t period; // trace write period in us + uint32_t wr_err; + uint32_t wr_cnt; +} esp_apptrace_test_gen_data_t; + +typedef struct { + int group; + int id; + void (*isr_func)(void *); + esp_apptrace_test_gen_data_t data; +} esp_apptrace_test_timer_arg_t; + +typedef struct { + int nowait; + int core; + int prio; + void (*task_func)(void *); + esp_apptrace_test_gen_data_t data; + volatile int stop; + SemaphoreHandle_t done; + + uint32_t timers_num; + esp_apptrace_test_timer_arg_t *timers; +} esp_apptrace_test_task_arg_t; + +typedef struct { + uint32_t tasks_num; + esp_apptrace_test_task_arg_t *tasks; +} esp_apptrace_test_cfg_t; + +#if ESP_APPTRACE_TEST_USE_PRINT_LOCK == 1 +static SemaphoreHandle_t s_print_lock; +#endif + +static uint64_t esp_apptrace_test_ts_get(); + +static void esp_apptrace_test_timer_init(int timer_group, int timer_idx, uint32_t period) +{ + timer_config_t config; + uint64_t alarm_val = (period * (TIMER_BASE_CLK / 1000000UL)) / 2; + + config.alarm_en = 1; + config.auto_reload = 1; + config.counter_dir = TIMER_COUNT_UP; + config.divider = 1; + config.intr_type = TIMER_INTR_LEVEL; + config.counter_en = TIMER_PAUSE; + /*Configure timer*/ + timer_init(timer_group, timer_idx, &config); + /*Stop timer counter*/ + timer_pause(timer_group, timer_idx); + /*Load counter value */ + timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); + /*Set alarm value*/ + timer_set_alarm_value(timer_group, timer_idx, alarm_val); + /*Enable timer interrupt*/ + timer_enable_intr(timer_group, timer_idx); +} + +static void esp_apptrace_test_timer_isr(void *arg) +{ + esp_apptrace_test_timer_arg_t *tim_arg = (esp_apptrace_test_timer_arg_t *)arg; + + uint32_t *ts = (uint32_t *)(tim_arg->data.buf + sizeof(uint32_t)); + *ts = (uint32_t)esp_apptrace_test_ts_get(); + memset(tim_arg->data.buf + 2 * sizeof(uint32_t), tim_arg->data.wr_cnt & tim_arg->data.mask, tim_arg->data.buf_sz - 2 * sizeof(uint32_t)); + int res = ESP_APPTRACE_TEST_WRITE_FROM_ISR(tim_arg->data.buf, tim_arg->data.buf_sz); + if (res != ESP_OK) { + } else { + if (0) { + ets_printf("tim-%d-%d: Written chunk%d %d bytes, %x\n", + tim_arg->group, tim_arg->id, tim_arg->data.wr_cnt, tim_arg->data.buf_sz, tim_arg->data.wr_cnt & tim_arg->data.mask); + } + tim_arg->data.wr_err = 0; + } + + tim_arg->data.wr_cnt++; + if (tim_arg->group == 0) { + if (tim_arg->id == 0) { + TIMERG0.int_clr_timers.t0 = 1; + TIMERG0.hw_timer[0].update = 1; + TIMERG0.hw_timer[0].config.alarm_en = 1; + } else { + TIMERG0.int_clr_timers.t1 = 1; + TIMERG0.hw_timer[1].update = 1; + TIMERG0.hw_timer[1].config.alarm_en = 1; + } + } + if (tim_arg->group == 1) { + if (tim_arg->id == 0) { + TIMERG1.int_clr_timers.t0 = 1; + TIMERG1.hw_timer[0].update = 1; + TIMERG1.hw_timer[0].config.alarm_en = 1; + } else { + TIMERG1.int_clr_timers.t1 = 1; + TIMERG1.hw_timer[1].update = 1; + TIMERG1.hw_timer[1].config.alarm_en = 1; + } + } +} + +static void esp_apptrace_test_timer_isr_crash(void *arg) +{ + esp_apptrace_test_timer_arg_t *tim_arg = (esp_apptrace_test_timer_arg_t *)arg; + + if (tim_arg->group == 0) { + if (tim_arg->id == 0) { + TIMERG0.int_clr_timers.t0 = 1; + TIMERG0.hw_timer[0].update = 1; + TIMERG0.hw_timer[0].config.alarm_en = 1; + } else { + TIMERG0.int_clr_timers.t1 = 1; + TIMERG0.hw_timer[1].update = 1; + TIMERG0.hw_timer[1].config.alarm_en = 1; + } + } + if (tim_arg->group == 1) { + if (tim_arg->id == 0) { + TIMERG1.int_clr_timers.t0 = 1; + TIMERG1.hw_timer[0].update = 1; + TIMERG1.hw_timer[0].config.alarm_en = 1; + } else { + TIMERG1.int_clr_timers.t1 = 1; + TIMERG1.hw_timer[1].update = 1; + TIMERG1.hw_timer[1].config.alarm_en = 1; + } + } + if (tim_arg->data.wr_cnt < ESP_APPTRACE_TEST_BLOCKS_BEFORE_CRASH) { + uint32_t *ts = (uint32_t *)(tim_arg->data.buf + sizeof(uint32_t)); + *ts = (uint32_t)esp_apptrace_test_ts_get();//xthal_get_ccount();//xTaskGetTickCount(); + memset(tim_arg->data.buf + 2 * sizeof(uint32_t), tim_arg->data.wr_cnt & tim_arg->data.mask, tim_arg->data.buf_sz - 2 * sizeof(uint32_t)); + int res = ESP_APPTRACE_TEST_WRITE_FROM_ISR(tim_arg->data.buf, tim_arg->data.buf_sz); + if (res != ESP_OK) { + ets_printf("tim-%d-%d: Failed to write trace %d %x!\n", tim_arg->group, tim_arg->id, res, tim_arg->data.wr_cnt & tim_arg->data.mask); + } else { + ets_printf("tim-%d-%d: Written chunk%d %d bytes, %x\n", + tim_arg->group, tim_arg->id, tim_arg->data.wr_cnt, tim_arg->data.buf_sz, tim_arg->data.wr_cnt & tim_arg->data.mask); + tim_arg->data.wr_cnt++; + } + } else { + uint32_t *ptr = 0; + *ptr = 1000; + } +} + +static void esp_apptrace_dummy_task(void *p) +{ + esp_apptrace_test_task_arg_t *arg = (esp_apptrace_test_task_arg_t *) p; + int res, flags = 0, i; + timer_isr_handle_t *inth = NULL; + TickType_t tmo_ticks = arg->data.period / (1000 * portTICK_PERIOD_MS); + + ESP_APPTRACE_TEST_LOGI("%x: run dummy task (period %u us, %u timers)", xTaskGetCurrentTaskHandle(), arg->data.period, arg->timers_num); + + if (arg->timers_num > 0) { + inth = pvPortMalloc(arg->timers_num * sizeof(timer_isr_handle_t)); + if (!inth) { + ESP_APPTRACE_TEST_LOGE("Failed to alloc timer ISR handles!"); + goto on_fail; + } + memset(inth, 0, arg->timers_num * sizeof(timer_isr_handle_t)); + for (int i = 0; i < arg->timers_num; i++) { + esp_apptrace_test_timer_init(arg->timers[i].group, arg->timers[i].id, arg->timers[i].data.period); + res = timer_isr_register(arg->timers[i].group, arg->timers[i].id, arg->timers[i].isr_func, &arg->timers[i], flags, &inth[i]); + if (res != ESP_OK) { + ESP_APPTRACE_TEST_LOGE("Failed to timer_isr_register (%d)!", res); + goto on_fail; + } + *(uint32_t *)arg->timers[i].data.buf = (uint32_t)inth[i] | (1 << 31); + ESP_APPTRACE_TEST_LOGI("%x: start timer %x period %u us", xTaskGetCurrentTaskHandle(), inth[i], arg->timers[i].data.period); + res = timer_start(arg->timers[i].group, arg->timers[i].id); + if (res != ESP_OK) { + ESP_APPTRACE_TEST_LOGE("Failed to timer_start (%d)!", res); + goto on_fail; + } + } + } + + i = 0; + while (!arg->stop) { + ESP_APPTRACE_TEST_LOGD("%x: dummy task work %d.%d", xTaskGetCurrentTaskHandle(), xPortGetCoreID(), i++); + if (tmo_ticks) { + vTaskDelay(tmo_ticks); + } + } + +on_fail: + if (inth) { + for (int i = 0; i < arg->timers_num; i++) { + timer_pause(arg->timers[i].group, arg->timers[i].id); + timer_disable_intr(arg->timers[i].group, arg->timers[i].id); + if (inth[i]) { + esp_intr_free(inth[i]); + } + } + vPortFree(inth); + } + xSemaphoreGive(arg->done); + vTaskDelay(1); + vTaskDelete(NULL); +} + +static void esp_apptrace_test_task(void *p) +{ + esp_apptrace_test_task_arg_t *arg = (esp_apptrace_test_task_arg_t *) p; + int res, flags = 0; + timer_isr_handle_t *inth = NULL; + TickType_t tmo_ticks = arg->data.period / (1000 * portTICK_PERIOD_MS); + + ESP_APPTRACE_TEST_LOGI("%x: run (period %u us, stamp mask %x, %u timers)", xTaskGetCurrentTaskHandle(), arg->data.period, arg->data.mask, arg->timers_num); + + if (arg->timers_num > 0) { + inth = pvPortMalloc(arg->timers_num * sizeof(timer_isr_handle_t)); + if (!inth) { + ESP_APPTRACE_TEST_LOGE("Failed to alloc timer ISR handles!"); + goto on_fail; + } + memset(inth, 0, arg->timers_num * sizeof(timer_isr_handle_t)); + for (int i = 0; i < arg->timers_num; i++) { + esp_apptrace_test_timer_init(arg->timers[i].group, arg->timers[i].id, arg->timers[i].data.period); + res = timer_isr_register(arg->timers[i].group, arg->timers[i].id, arg->timers[i].isr_func, &arg->timers[i], flags, &inth[i]); + if (res != ESP_OK) { + ESP_APPTRACE_TEST_LOGE("Failed to timer_isr_register (%d)!", res); + goto on_fail; + } + *(uint32_t *)arg->timers[i].data.buf = ((uint32_t)inth[i]) | (1 << 31) | (xPortGetCoreID() ? 0x1 : 0); + ESP_APPTRACE_TEST_LOGI("%x: start timer %x period %u us", xTaskGetCurrentTaskHandle(), inth[i], arg->timers[i].data.period); + res = timer_start(arg->timers[i].group, arg->timers[i].id); + if (res != ESP_OK) { + ESP_APPTRACE_TEST_LOGE("Failed to timer_start (%d)!", res); + goto on_fail; + } + } + } + + *(uint32_t *)arg->data.buf = (uint32_t)xTaskGetCurrentTaskHandle() | (xPortGetCoreID() ? 0x1 : 0); + arg->data.wr_cnt = 0; + arg->data.wr_err = 0; + while (!arg->stop) { + uint32_t *ts = (uint32_t *)(arg->data.buf + sizeof(uint32_t)); + *ts = (uint32_t)esp_apptrace_test_ts_get(); + memset(arg->data.buf + 2 * sizeof(uint32_t), arg->data.wr_cnt & arg->data.mask, arg->data.buf_sz - 2 * sizeof(uint32_t)); + if (arg->nowait) { + res = ESP_APPTRACE_TEST_WRITE_NOWAIT(arg->data.buf, arg->data.buf_sz); + } else { + res = ESP_APPTRACE_TEST_WRITE(arg->data.buf, arg->data.buf_sz); + } + if (res) { + if (arg->data.wr_err++ < ESP_APPTRACE_TEST_PRN_WRERR_MAX) { + ESP_APPTRACE_TEST_LOGE("%x: Failed to write trace %d %x!", xTaskGetCurrentTaskHandle(), res, arg->data.wr_cnt & arg->data.mask); + if (arg->data.wr_err == ESP_APPTRACE_TEST_PRN_WRERR_MAX) { + ESP_APPTRACE_TEST_LOGE("\n"); + } + } + } else { + if (0) { + ESP_APPTRACE_TEST_LOGD("%x:%x: Written chunk%d %d bytes, %x", xTaskGetCurrentTaskHandle(), *ts, arg->data.wr_cnt, arg->data.buf_sz, arg->data.wr_cnt & arg->data.mask); + } + arg->data.wr_err = 0; + } + arg->data.wr_cnt++; + if (tmo_ticks) { + vTaskDelay(tmo_ticks); + } + } + +on_fail: + if (inth) { + for (int i = 0; i < arg->timers_num; i++) { + timer_pause(arg->timers[i].group, arg->timers[i].id); + timer_disable_intr(arg->timers[i].group, arg->timers[i].id); + if (inth[i]) { + esp_intr_free(inth[i]); + } + } + vPortFree(inth); + } + xSemaphoreGive(arg->done); + vTaskDelay(1); + vTaskDelete(NULL); +} + +static void esp_apptrace_test_task_crash(void *p) +{ + esp_apptrace_test_task_arg_t *arg = (esp_apptrace_test_task_arg_t *) p; + int res, i; + + ESP_APPTRACE_TEST_LOGE("%x: run (period %u us, stamp mask %x, %u timers)", xTaskGetCurrentTaskHandle(), arg->data.period, arg->data.mask, arg->timers_num); + + arg->data.wr_cnt = 0; + *(uint32_t *)arg->data.buf = (uint32_t)xTaskGetCurrentTaskHandle(); + for (i = 0; i < ESP_APPTRACE_TEST_BLOCKS_BEFORE_CRASH; i++) { + uint32_t *ts = (uint32_t *)(arg->data.buf + sizeof(uint32_t)); + *ts = (uint32_t)esp_apptrace_test_ts_get(); + memset(arg->data.buf + sizeof(uint32_t), arg->data.wr_cnt & arg->data.mask, arg->data.buf_sz - sizeof(uint32_t)); + res = ESP_APPTRACE_TEST_WRITE(arg->data.buf, arg->data.buf_sz); + if (res) { + ESP_APPTRACE_TEST_LOGE("%x: Failed to write trace %d %x!", xTaskGetCurrentTaskHandle(), res, arg->data.wr_cnt & arg->data.mask); + } else { + ESP_APPTRACE_TEST_LOGD("%x: Written chunk%d %d bytes, %x", xTaskGetCurrentTaskHandle(), arg->data.wr_cnt, arg->data.buf_sz, arg->data.wr_cnt & arg->data.mask); + } + arg->data.wr_cnt++; + } + vTaskDelay(500); + uint32_t *ptr = 0; + *ptr = 1000; + + xSemaphoreGive(arg->done); + vTaskDelay(1); + vTaskDelete(NULL); +} + +static int s_ts_timer_group, s_ts_timer_idx; + +static uint64_t esp_apptrace_test_ts_get() +{ + uint64_t ts = 0; + timer_get_counter_value(s_ts_timer_group, s_ts_timer_idx, &ts); + return ts; +} + +static void esp_apptrace_test_ts_init(int timer_group, int timer_idx) +{ + timer_config_t config; + //uint64_t alarm_val = period * (TIMER_BASE_CLK / 1000000UL); + + ESP_APPTRACE_TEST_LOGI("Use timer%d.%d for TS", timer_group, timer_idx); + + s_ts_timer_group = timer_group; + s_ts_timer_idx = timer_idx; + + config.alarm_en = 0; + config.auto_reload = 0; + config.counter_dir = TIMER_COUNT_UP; + config.divider = 1; + config.counter_en = 0; + /*Configure timer*/ + timer_init(timer_group, timer_idx, &config); + /*Load counter value */ + timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); + /*Enable timer interrupt*/ + timer_start(timer_group, timer_idx); +} + +static void esp_apptrace_test_ts_cleanup() +{ + timer_config_t config; + + config.alarm_en = 0; + config.auto_reload = 0; + config.counter_dir = TIMER_COUNT_UP; + config.divider = 1; + config.counter_en = 0; + /*Configure timer*/ + timer_init(s_ts_timer_group, s_ts_timer_idx, &config); +} + +static void esp_apptrace_test(esp_apptrace_test_cfg_t *test_cfg) +{ + int i, k; + int tims_in_use[TIMER_GROUP_MAX][TIMER_MAX] = {{0, 0}, {0, 0}}; + esp_apptrace_test_task_arg_t dummy_task_arg[1]; + + memset(dummy_task_arg, 0, sizeof(dummy_task_arg)); + dummy_task_arg[0].core = 0; + dummy_task_arg[0].prio = 3; + dummy_task_arg[0].task_func = esp_apptrace_test_task_crash; + dummy_task_arg[0].data.buf = NULL; + dummy_task_arg[0].data.buf_sz = 0; + dummy_task_arg[0].data.period = 500000; + dummy_task_arg[0].timers_num = 0; + dummy_task_arg[0].timers = NULL; +#if ESP_APPTRACE_TEST_USE_PRINT_LOCK == 1 + s_print_lock = xSemaphoreCreateBinary(); + if (!s_print_lock) { + ets_printf("%s: Failed to create print lock!", TAG); + return; + } + xSemaphoreGive(s_print_lock); +#else +#endif + + for (i = 0; i < test_cfg->tasks_num; i++) { + test_cfg->tasks[i].data.mask = 0xFF; + test_cfg->tasks[i].stop = 0; + test_cfg->tasks[i].done = xSemaphoreCreateBinary(); + if (!test_cfg->tasks[i].done) { + ESP_APPTRACE_TEST_LOGE("Failed to create task completion semaphore!"); + goto on_fail; + } + for (k = 0; k < test_cfg->tasks[i].timers_num; k++) { + test_cfg->tasks[i].timers[k].data.mask = 0xFF; + tims_in_use[test_cfg->tasks[i].timers[k].group][test_cfg->tasks[i].timers[k].id] = 1; + } + } + + int found = 0; + for (i = 0; i < TIMER_GROUP_MAX; i++) { + for (k = 0; k < TIMER_MAX; k++) { + if (!tims_in_use[i][k]) { + ESP_APPTRACE_TEST_LOGD("Found timer%d.%d", i, k); + found = 1; + break; + } + } + if (found) { + break; + } + } + if (!found) { + ESP_APPTRACE_TEST_LOGE("No free timer for TS!"); + goto on_fail; + } + esp_apptrace_test_ts_init(i, k); + + for (int i = 0; i < test_cfg->tasks_num; i++) { + char name[30]; + TaskHandle_t thnd; + sprintf(name, "apptrace_test%d", i); + xTaskCreatePinnedToCore(test_cfg->tasks[i].task_func, name, 2048, &test_cfg->tasks[i], test_cfg->tasks[i].prio, &thnd, test_cfg->tasks[i].core); + ESP_APPTRACE_TEST_LOGI("Created task %x", thnd); + } + xTaskCreatePinnedToCore(esp_apptrace_dummy_task, "dummy0", 2048, &dummy_task_arg[0], dummy_task_arg[0].prio, NULL, 0); + xTaskCreatePinnedToCore(esp_apptrace_dummy_task, "dummy1", 2048, &dummy_task_arg[0], dummy_task_arg[0].prio, NULL, 1); + + for (int i = 0; i < test_cfg->tasks_num; i++) { + //arg1.stop = 1; + xSemaphoreTake(test_cfg->tasks[i].done, portMAX_DELAY); + } + +on_fail: + for (int i = 0; i < test_cfg->tasks_num; i++) { + if (test_cfg->tasks[i].done) { + vSemaphoreDelete(test_cfg->tasks[i].done); + } + } + esp_apptrace_test_ts_cleanup(); + +#if ESP_APPTRACE_TEST_USE_PRINT_LOCK == 1 + vSemaphoreDelete(s_print_lock); +#else +#endif +} + +static esp_apptrace_test_task_arg_t s_test_tasks[4]; +static esp_apptrace_test_timer_arg_t s_test_timers[2]; +static uint8_t s_bufs[6][ESP_APPTRACE_TEST_BLOCK_SIZE]; + +TEST_CASE("App trace test (1 task + 1 crashed timer ISR @ 1 core)", "[trace][ignore]") +{ + esp_apptrace_test_cfg_t test_cfg = { + .tasks_num = 1, + .tasks = s_test_tasks, + }; + + memset(s_test_timers, 0, sizeof(s_test_timers)); + memset(s_test_tasks, 0, sizeof(s_test_tasks)); + + s_test_timers[0].group = TIMER_GROUP_0; + s_test_timers[0].id = TIMER_0; + s_test_timers[0].isr_func = esp_apptrace_test_timer_isr_crash; + s_test_timers[0].data.buf = s_bufs[0]; + s_test_timers[0].data.buf_sz = sizeof(s_bufs[0]); + s_test_timers[0].data.period = 1000; + + s_test_tasks[0].core = 0; + s_test_tasks[0].prio = 3; + s_test_tasks[0].task_func = esp_apptrace_dummy_task; + s_test_tasks[0].data.buf = NULL; + s_test_tasks[0].data.buf_sz = 0; + s_test_tasks[0].data.period = 1000000; + s_test_tasks[0].timers_num = 1; + s_test_tasks[0].timers = s_test_timers; + + esp_apptrace_test(&test_cfg); +} + + +TEST_CASE("App trace test (1 crashed task)", "[trace][ignore]") +{ + esp_apptrace_test_task_arg_t s_test_tasks[1]; + esp_apptrace_test_cfg_t test_cfg = { + .tasks_num = 1, + .tasks = s_test_tasks, + }; + + memset(s_test_tasks, 0, sizeof(s_test_tasks)); + + s_test_tasks[0].core = 0; + s_test_tasks[0].prio = 3; + s_test_tasks[0].task_func = esp_apptrace_test_task_crash; + s_test_tasks[0].data.buf = s_bufs[0]; + s_test_tasks[0].data.buf_sz = sizeof(s_bufs[0]); + s_test_tasks[0].data.period = 6000; + s_test_tasks[0].timers_num = 0; + s_test_tasks[0].timers = NULL; + + esp_apptrace_test(&test_cfg); +} + +TEST_CASE("App trace test (2 tasks + 1 timer @ each core", "[trace][ignore]") +{ + int ntask = 0; + esp_apptrace_test_cfg_t test_cfg = { + .tasks_num = 4, + .tasks = s_test_tasks, + }; + + memset(s_test_tasks, 0, sizeof(s_test_tasks)); + memset(s_test_timers, 0, sizeof(s_test_timers)); + + s_test_timers[0].group = TIMER_GROUP_0; + s_test_timers[0].id = TIMER_0; + s_test_timers[0].isr_func = esp_apptrace_test_timer_isr; + s_test_timers[0].data.buf = s_bufs[0]; + s_test_timers[0].data.buf_sz = sizeof(s_bufs[0]); + s_test_timers[0].data.period = 150; + + s_test_timers[1].group = TIMER_GROUP_1; + s_test_timers[1].id = TIMER_0; + s_test_timers[1].isr_func = esp_apptrace_test_timer_isr; + s_test_timers[1].data.buf = s_bufs[1]; + s_test_timers[1].data.buf_sz = sizeof(s_bufs[1]); + s_test_timers[1].data.period = 150; + + s_test_tasks[ntask].core = 0; + s_test_tasks[ntask].prio = 4; + s_test_tasks[ntask].task_func = esp_apptrace_test_task; + s_test_tasks[ntask].data.buf = s_bufs[2]; + s_test_tasks[ntask].data.buf_sz = sizeof(s_bufs[2]); + s_test_tasks[ntask].data.period = 1000; + s_test_tasks[ntask].timers_num = 1; + s_test_tasks[ntask].timers = &s_test_timers[0]; + ntask++; + s_test_tasks[ntask].core = 0; + s_test_tasks[ntask].prio = 3; + s_test_tasks[ntask].task_func = esp_apptrace_test_task; + s_test_tasks[ntask].data.buf = s_bufs[3]; + s_test_tasks[ntask].data.buf_sz = sizeof(s_bufs[3]); + s_test_tasks[ntask].data.period = 0; + s_test_tasks[ntask].timers_num = 0; + s_test_tasks[ntask].timers = NULL; + ntask++; + s_test_tasks[ntask].core = 1; + s_test_tasks[ntask].prio = 4; + s_test_tasks[ntask].task_func = esp_apptrace_test_task; + s_test_tasks[ntask].data.buf = s_bufs[4]; + s_test_tasks[ntask].data.buf_sz = sizeof(s_bufs[4]); + s_test_tasks[ntask].data.period = 1000; + s_test_tasks[ntask].timers_num = 1; + s_test_tasks[ntask].timers = &s_test_timers[1]; + ntask++; + s_test_tasks[ntask].core = 1; + s_test_tasks[ntask].prio = 3; + s_test_tasks[ntask].task_func = esp_apptrace_test_task; + s_test_tasks[ntask].data.buf = s_bufs[5]; + s_test_tasks[ntask].data.buf_sz = sizeof(s_bufs[5]); + s_test_tasks[ntask].data.period = 0; + s_test_tasks[ntask].timers_num = 0; + s_test_tasks[ntask].timers = NULL; + ntask++; + + esp_apptrace_test(&test_cfg); +} + +TEST_CASE("App trace test (1 task + 1 timer @ 1 core)", "[trace][ignore]") +{ + esp_apptrace_test_cfg_t test_cfg = { + .tasks_num = 1, + .tasks = s_test_tasks, + }; + + memset(s_test_timers, 0, sizeof(s_test_timers)); + memset(s_test_tasks, 0, sizeof(s_test_tasks)); + + s_test_timers[0].group = TIMER_GROUP_0; + s_test_timers[0].id = TIMER_0; + s_test_timers[0].isr_func = esp_apptrace_test_timer_isr; + s_test_timers[0].data.buf = s_bufs[0]; + s_test_timers[0].data.buf_sz = sizeof(s_bufs[0]); + s_test_timers[0].data.period = 150; + + s_test_tasks[0].core = 0; + s_test_tasks[0].prio = 3; + s_test_tasks[0].task_func = esp_apptrace_test_task; + s_test_tasks[0].data.buf = s_bufs[1]; + s_test_tasks[0].data.buf_sz = sizeof(s_bufs[1]); + s_test_tasks[0].data.period = 0; + s_test_tasks[0].timers_num = 1; + s_test_tasks[0].timers = s_test_timers; + + esp_apptrace_test(&test_cfg); +} + +TEST_CASE("App trace test (2 tasks (nowait): 1 @ each core)", "[trace][ignore]") +{ + esp_apptrace_test_cfg_t test_cfg = { + .tasks_num = 2, + .tasks = s_test_tasks, + }; + + memset(s_test_tasks, 0, sizeof(s_test_tasks)); + + s_test_tasks[0].nowait = 1; + s_test_tasks[0].core = 0; + s_test_tasks[0].prio = 3; + s_test_tasks[0].task_func = esp_apptrace_test_task; + s_test_tasks[0].data.buf = s_bufs[0]; + s_test_tasks[0].data.buf_sz = sizeof(s_bufs[0]); + s_test_tasks[0].data.period = 6700; + s_test_tasks[0].timers_num = 0; + s_test_tasks[0].timers = NULL; + + s_test_tasks[1].nowait = 1; + s_test_tasks[1].core = 1; + s_test_tasks[1].prio = 3; + s_test_tasks[1].task_func = esp_apptrace_test_task; + s_test_tasks[1].data.buf = s_bufs[1]; + s_test_tasks[1].data.buf_sz = sizeof(s_bufs[1]); + s_test_tasks[1].data.period = 6700; + s_test_tasks[1].timers_num = 0; + s_test_tasks[1].timers = NULL; + + esp_apptrace_test(&test_cfg); +} + +TEST_CASE("App trace test (2 tasks: 1 @ each core)", "[trace][ignore]") +{ + esp_apptrace_test_cfg_t test_cfg = { + .tasks_num = 2, + .tasks = s_test_tasks, + }; + + memset(s_test_tasks, 0, sizeof(s_test_tasks)); + + s_test_tasks[0].core = 0; + s_test_tasks[0].prio = 3; + s_test_tasks[0].task_func = esp_apptrace_test_task; + s_test_tasks[0].data.buf = s_bufs[0]; + s_test_tasks[0].data.buf_sz = sizeof(s_bufs[0]); + s_test_tasks[0].data.period = 0; + s_test_tasks[0].timers_num = 0; + s_test_tasks[0].timers = NULL; + + s_test_tasks[1].core = 1; + s_test_tasks[1].prio = 3; + s_test_tasks[1].task_func = esp_apptrace_test_task; + s_test_tasks[1].data.buf = s_bufs[1]; + s_test_tasks[1].data.buf_sz = sizeof(s_bufs[1]); + s_test_tasks[1].data.period = 0; + s_test_tasks[1].timers_num = 0; + s_test_tasks[1].timers = NULL; + + esp_apptrace_test(&test_cfg); +} + +TEST_CASE("App trace test (1 task)", "[trace][ignore]") +{ + esp_apptrace_test_cfg_t test_cfg = { + .tasks_num = 1, + .tasks = s_test_tasks, + }; + + memset(s_test_tasks, 0, sizeof(s_test_tasks)); + + s_test_tasks[0].core = 1; + s_test_tasks[0].prio = 3; + s_test_tasks[0].task_func = esp_apptrace_test_task; + s_test_tasks[0].data.buf = s_bufs[0]; + s_test_tasks[0].data.buf_sz = sizeof(s_bufs[0]); + s_test_tasks[0].data.period = 0; + s_test_tasks[0].timers_num = 0; + s_test_tasks[0].timers = NULL; + + esp_apptrace_test(&test_cfg); +} + +static int esp_logtrace_printf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + int ret = esp_apptrace_vprintf_to(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TMO_INFINITE, fmt, ap); + + va_end(ap); + + return ret; +} + +typedef struct { + SemaphoreHandle_t done; +} esp_logtrace_task_t; + +static void esp_logtrace_task(void *p) +{ + esp_logtrace_task_t *arg = (esp_logtrace_task_t *) p; + + ESP_APPTRACE_TEST_LOGI("%x: run log test task", xTaskGetCurrentTaskHandle()); + + int i = 0; + while (1) { + esp_logtrace_printf("sample print %lx %hx %c\n", 2 * i + 0x10, 2 * i + 0x20, (2 * i + 0x30) & 0xFF); + esp_logtrace_printf("sample print %lx %hx %c %lu %hu %d %d %d %d\n", i, i + 0x10, (i + 0x20) & 0xFF, i + 0x30, i + 0x40, i + 0x50, i + 0x60, i + 0x70, i + 0x80); + ESP_LOGI(TAG, "%p: sample print 1", xTaskGetCurrentTaskHandle()); + ESP_LOGI(TAG, "%p: sample print 2 %u", xTaskGetCurrentTaskHandle(), (unsigned)i); + ESP_LOGI(TAG, "%p: sample print 4 %c", xTaskGetCurrentTaskHandle(), ((i & 0xFF) % 95) + 32); + ESP_LOGI(TAG, "%p: sample print 5 %f", xTaskGetCurrentTaskHandle(), 1.0); + ESP_LOGI(TAG, "%p: sample print 6 %f", xTaskGetCurrentTaskHandle(), 3.45); + ESP_LOGI(TAG, "%p: logtrace task work %d.%d", xTaskGetCurrentTaskHandle(), xPortGetCoreID(), i); + if (++i == 10000) { + break; + } + } + esp_err_t ret = esp_apptrace_flush(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TMO_INFINITE); + if (ret != ESP_OK) { + ESP_APPTRACE_TEST_LOGE("Failed to flush printf buf (%d)!", ret); + } + + ESP_APPTRACE_TEST_LOGI("%x: finished", xTaskGetCurrentTaskHandle()); + + xSemaphoreGive(arg->done); + vTaskDelay(1); + vTaskDelete(NULL); +} + +TEST_CASE("Log trace test (1 task)", "[trace][ignore]") +{ + TaskHandle_t thnd; + + esp_logtrace_task_t arg1 = { + .done = xSemaphoreCreateBinary(), + }; + esp_logtrace_task_t arg2 = { + .done = xSemaphoreCreateBinary(), + }; + + xTaskCreatePinnedToCore(esp_logtrace_task, "logtrace0", 2048, &arg1, 3, &thnd, 0); + ESP_APPTRACE_TEST_LOGI("Created task %x", thnd); + xTaskCreatePinnedToCore(esp_logtrace_task, "logtrace1", 2048, &arg2, 3, &thnd, 1); + ESP_APPTRACE_TEST_LOGI("Created task %x", thnd); + + xSemaphoreTake(arg1.done, portMAX_DELAY); + vSemaphoreDelete(arg1.done); + xSemaphoreTake(arg2.done, portMAX_DELAY); + vSemaphoreDelete(arg2.done); +} +#endif diff --git a/components/freertos/port.c b/components/freertos/port.c index 756e14295..83b793c9d 100644 --- a/components/freertos/port.c +++ b/components/freertos/port.c @@ -255,7 +255,6 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMOR } #endif - /* * Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs * aren't detected here, but they normally cannot call C code, so that should not be an issue anyway. diff --git a/components/log/README.rst b/components/log/README.rst index 002dadf81..f732a9e90 100644 --- a/components/log/README.rst +++ b/components/log/README.rst @@ -59,3 +59,136 @@ To configure logging output per module at runtime, add calls to ``esp_log_level_ esp_log_level_set("wifi", ESP_LOG_WARN); // enable WARN logs from WiFi stack esp_log_level_set("dhcpc", ESP_LOG_INFO); // enable INFO logs from DHCP client +Logging to Host via JTAG +^^^^^^^^^^^^^^^^^^^^^^^^ + +By default logging library uses vprintf-like function to write formatted output to dedicated UART. In general it invloves the following steps: + +1. Format string is parsed to obtain type of each argument. +2. According to its type every argument is converted to string representation. +3. Format string combined with converted arguments is sent to UART. + +Though implementation of vprintf-like function can be optimised to a certain level, all steps above have to be peformed in any case and every step takes some time (especially item 3). So it is frequent situation when addition of extra logging to the program to diagnose some problem changes its behaviour and problem dissapears or in the worst cases program can not work normally at all and ends up with an error or even hangs. +Possible ways to overcome this problem are to use faster UART bitrates (or another faster interface) and/or move string formatting procedure to the host. +ESP IDF has `Application Tracing` feature which allows to sent arbitrary application data to host via JTAG. This feature can also be used to transfer log information to host using ``esp_apptrace_vprintf`` function. This function does not perform full parsing of the format string and arguments, instead it just calculates number of arguments passed and sends them along with the format string address to the host. On the host log data are processed and printed out by a special Python script. + +Config Options and Dependencies +""""""""""""""""""""""""""""""" + +Using of the feature depends on two components: + +1. Host side: Application tracing is done over JTAG, so it needs OpenOCD to be set up and running on host machine. For instructions how to set it up, please, see :idf:`OpenOCD setup for ESP32` section for details. **NOTE:** `in order to achieve higher data rates you may need to modify JTAG adapter working frequency in OpenOCD config file. Maximum tested stable speed is 26MHz, so you need to have the following statement in your configuration file` ``adapter_khz 26000`` `instead of default` ``adapter_khz 200``. `Actually maximum stable JTAG frequency can depend on host system configuration.` +2. Target side: Application tracing functionality can be enabled by ``CONFIG_ESP32_APPTRACE_ENABLE`` macro via menuconfig. This option enables the module and makes ``esp_apptrace_vprintf`` available for users. + +Limitations +""""""""""" + +Curent implmentation of logging over JTAG has several limitations: + +1. Tracing from ``ESP_EARLY_LOGx`` macros is not supported. +2. No support for printf arguments which size exceeds 4 bytes (e.g. ``double`` and ``uint64_t``). +3. Only strings from .rodata section are supported as format strings and arguments. +4. Maximum number of printf arguments is 256. + +How To Use It +""""""""""""" + +To use logging via JTAG user needs to perform the following steps: + +1. On target side special vprintf-like function needs to be installed. As it was mentioned earlier this function is ``esp_apptrace_vprintf``. It sends log data to the host via JTAG. Example code is shown below. + +.. code-block:: c + + #include "esp_app_trace.h" + ... + void app_main() + { + // set log vprintf handler + esp_log_set_vprintf(esp_apptrace_vprintf); + ... + // user code using ESP_LOGx starts here + // all data passed to ESP_LOGx are sent to host + ... + // restore log vprintf handler + esp_log_set_vprintf(vprintf); + // flush last data to host + esp_apptrace_flush(ESP_APPTRACE_DEST_TRAX, 100000 /*tmo in us*/); + ESP_LOGI(TAG, "Tracing is finished."); // this will be printed out to UART + while (1); + } + +2. Build the program image and download it to target as described in :idf:`Developing With the ESP-IDF` section. +3. Run OpenOCD (see :idf:`OpenOCD setup for ESP32` section). +4. Connect to OpenOCD telnet server. On Linux it can be done using the following command in terminal ``telnet 4444``. If telnet session is opened on the same machine which runs OpenOCD you can use `localhost` as `` in the command. +5. Run the following command in OpenOCD telnet session: ``esp108 apptrace start /path/to/trace/file -1 -1 0 0 1``. This command will wait for board reset and transfer tracing data at the highest possible rate. +6. Reset the board. Logging to host will start automatically. +7. ``esp108 apptrace`` command with given arguments will never return (see other command options below), so you must stop it manually by resetting the board or pressing CTRL+C in OpenOCD window (not one with the telnet session). +8. Reset board or press CTRL+C in OpenOCD window (not one with the telnet session) when tracing is completed (for the example code above after the message `"Tracing is finished."` appears on UART). +9. To print out collected log records run the following command in terminal: ``$IDF_PATH/tools/esp_app_trace/logtrace_proc.py /path/to/trace/file /path/to/program/elf/file``. + +OpenOCD Application Tracing Command Options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Command usage: +``esp108 apptrace [start [options] | [stop] | [status] | [dump ]`` + +Sub-commands: + * ``start``. Start tracing (continuous streaming). + * ``stop``. Stop tracing. + * ``status``. Get tracing status. + * ``dump``. Dump as much data as possible without waiting for trace memory block switch (post-mortem dump). + +Start command syntax: + ``start [trace_size [stop_tmo [skip_size [poll_period [wait4halt]]]]]`` + + .. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - Argument + - Description + * - outfile + - Path to log trace file to save data + * - trace_size + - Maximum size of data to collect (in bytes). Tracing is stopped after specified amount of data is received. By default -1 (trace size stop trigger is disabled). + * - stop_tmo + - Idle timeout (in ms). Tracing is stopped if there is no data for specified period of time. By default 10 s (-1 to disable this stop trigger). + * - skip_size + - Number of bytes to skip at the start. By default 0. + * - poll_period + - Data polling period (in ms). If greater then 0 then command runs in non-blocking mode, otherwise command line will not be avalable until tracing is stopped. By default 1 ms. + * - wait4halt + - If 0 start tracing immediately, otherwise command waits for the target to be halted (after reset, by breakpoint etc) and then automatically resumes it and starts tracing. By default 0. + +Log Trace Processor Command Options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Command usage: +``logtrace_proc.py [-h] [--no-errors] `` + +Positional arguments: + + .. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - Argument + - Description + * - trace_file + - Path to log trace file + * - elf_file + - Path to program ELF file + +Optional arguments: + + .. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - Argument + - Description + * - -h, --help + - show this help message and exit + * - --no-errors, -n + - Do not print errors + diff --git a/components/xtensa-debug-module/trax.c b/components/xtensa-debug-module/trax.c index 5174e4477..15a125584 100644 --- a/components/xtensa-debug-module/trax.c +++ b/components/xtensa-debug-module/trax.c @@ -30,11 +30,11 @@ static const char* TAG = "trax"; int trax_enable(trax_ena_select_t which) { -#if !CONFIG_MEMMAP_TRACEMEM +#if !CONFIG_ESP32_TRAX ESP_LOGE(TAG, "Trax_enable called, but trax is disabled in menuconfig!"); return ESP_ERR_NO_MEM; #endif -#if !CONFIG_MEMMAP_TRACEMEM_TWOBANKS +#if !CONFIG_ESP32_TRAX_TWOBANKS if (which == TRAX_ENA_PRO_APP || which == TRAX_ENA_PRO_APP_SWAP) return ESP_ERR_NO_MEM; #endif if (which == TRAX_ENA_PRO_APP || which == TRAX_ENA_PRO_APP_SWAP) { @@ -50,7 +50,7 @@ int trax_enable(trax_ena_select_t which) int trax_start_trace(trax_downcount_unit_t units_until_stop) { -#if !CONFIG_MEMMAP_TRACEMEM +#if !CONFIG_ESP32_TRAX ESP_LOGE(TAG, "Trax_start_trace called, but trax is disabled in menuconfig!"); return ESP_ERR_NO_MEM; #endif @@ -74,7 +74,7 @@ int trax_start_trace(trax_downcount_unit_t units_until_stop) int trax_trigger_traceend_after_delay(int delay) { -#if !CONFIG_MEMMAP_TRACEMEM +#if !CONFIG_ESP32_TRAX ESP_LOGE(TAG, "Trax_trigger_traceend_after_delay called, but trax is disabled in menuconfig!"); return ESP_ERR_NO_MEM; #endif diff --git a/tools/esp_app_trace/apptrace_proc.py b/tools/esp_app_trace/apptrace_proc.py new file mode 100755 index 000000000..d676b0c06 --- /dev/null +++ b/tools/esp_app_trace/apptrace_proc.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python +# + +import argparse +import struct +import sys + +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + +def main(): + ESP32_TRACE_BLOCK_HDR_SZ = 8 + ESP32_TRACE_BLOCK_TASK_IDX = 0 + ESP32_TRACE_BLOCK_TS_IDX = 1 + ESP32_TRACE_BLOCK_DATA_IDX = 2 + + parser = argparse.ArgumentParser(description='ESP32 App Trace Parse Tool') + + parser.add_argument('file', help='Path to app trace file', type=str) + parser.add_argument('--print-tasks', '-p', help='Print tasks', action='store_true') + parser.add_argument('--print-details', '-d', help='Print detailed stats', action='store_true') + parser.add_argument('--no-errors', '-n', help='Do not print errors', action='store_true') + parser.add_argument('--block-len', '-b', help='Block length', type=int, default=1024) + + args = parser.parse_args() + + print "====================================================================" + try: + ftrc = open(args.file, 'rb') + except IOError as e: + print "Failed to open trace file (%s)!" % e + sys.exit(2) + + passed = True + off = 0 + data_stats = {} + last_ts = None + tot_discont = 0 + while True: + #ftrc.seek(off) + task = None + ts = 0 + trc_buf = ftrc.read(args.block_len) + if len(trc_buf) == 0: +# print 'EOF' + break + trc_data = struct.unpack('= ts: +# print "Global TS discontinuity %x -> %x, task %x, stamp %x at %x" % (last_ts, ts, task, data_stats[task]['stamp'], off) + if args.print_details: + print "Global TS discontinuity %x -> %x, task %x at %x" % (last_ts, ts, task, off) +# tot_discont += 1 +# passed = False + last_ts = ts + if not task in data_stats: + print "%x: NEW TASK" % task + data_stats[task] = {'stamp' : trc_data[ESP32_TRACE_BLOCK_DATA_IDX], 'last_ts' : ts, 'count' : 1, 'discont_offs' : [], 'inv_stamps_offs' : []} + else: + if data_stats[task]['last_ts'] == ts: + print "Task TS discontinuity %x -> %x, task %x, stamp %x at %x" % (last_ts, ts, task, data_stats[task]['stamp'], off) + data_stats[task]['discont_offs'].append(off) + tot_discont += 1 + passed = False + data_stats[task]['last_ts'] = ts + data_stats[task]['count'] += 1 + if len(trc_data) > ESP32_TRACE_BLOCK_DATA_IDX: +# print "DATA = %x %x %x %x" % (trc_data[-4], trc_data[-3], trc_data[-2], trc_data[-1]) + if args.print_tasks: + print "Task[%d] %x, ts %08x, stamp %x" % (off/args.block_len, task, ts, trc_data[ESP32_TRACE_BLOCK_DATA_IDX]) + else: + print "%x: NO DATA" % task + else: + print "Failed to unpack data!" + sys.exit(2) + + # check data + for i in range(ESP32_TRACE_BLOCK_DATA_IDX, len(trc_data)): + if trc_data[i] != data_stats[task]['stamp']: + if not args.no_errors: + print "Invalid stamp %x->%x at %x, task %x" % (data_stats[task]['stamp'], trc_data[i], off + ESP32_TRACE_BLOCK_HDR_SZ + i, task) + passed = False + data_stats[task]['stamp'] = trc_data[i] + data_stats[task]['inv_stamps_offs'].append(off) +# break + if len(trc_buf) < args.block_len: + print 'Last block (not full)' + break + + if data_stats[task]['stamp'] != None: + data_stats[task]['stamp'] = (data_stats[task]['stamp'] + 1) & 0xFF +# print "stamp=%x" % data_stats[task][ESP32_TRACE_STAMP_IDX] + off += args.block_len + + ftrc.close() + print "====================================================================" + print "Trace size %d bytes, discont %d\n" % (off, tot_discont) + for t in data_stats: + print "Task %x. Total count %d. Inv stamps %d. TS Discontinuities %d." % (t, data_stats[t]['count'], len(data_stats[t]['inv_stamps_offs']), len(data_stats[t]['discont_offs'])) + if args.print_details: + print 'Invalid stamps offs: [{}]'.format(', '.join(hex(x) for x in data_stats[t]['inv_stamps_offs'])) + print 'TS Discontinuities offs: [{}]'.format(', '.join(hex(x) for x in data_stats[t]['discont_offs'])) + print "\n" + + if passed: + print "Data - OK" + else: + print "Data - FAILED!" + +if __name__ == '__main__': + main() diff --git a/tools/esp_app_trace/logtrace_proc.py b/tools/esp_app_trace/logtrace_proc.py new file mode 100755 index 000000000..74860252a --- /dev/null +++ b/tools/esp_app_trace/logtrace_proc.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python +# + +import argparse +import struct +import sys +import pylibelf as elf +import pylibelf.util as elfutil +import pylibelf.iterators as elfiter +import pylibelf.constants as elfconst +from ctypes import * + +class ESPLogTraceParserError(RuntimeError): + def __init__(self, message): + RuntimeError.__init__(self, message) + + +class ESPLogTraceRecord(object): + def __init__(self, fmt_addr, log_args): + super(ESPLogTraceRecord, self).__init__() + self.fmt_addr = fmt_addr + self.args = log_args + + def __repr__(self): + return "fmt_addr = 0x%x, args = %d/%s" % (self.fmt_addr, len(self.args), self.args) + + +def logtrace_parse(fname): + ESP32_LOGTRACE_HDR_FMT = ' 0: + print "Unprocessed %d bytes of log record header!" % len(trc_buf) + # data_ok = False + break + try: + nargs,fmt_addr = struct.unpack(ESP32_LOGTRACE_HDR_FMT, trc_buf) + except struct.error as e: + raise ESPLogTraceParserError("Failed to unpack log record header (%s)!" % e) + # read args + args_sz = struct.calcsize('<%sL' % nargs) + try: + trc_buf = ftrc.read(args_sz) + except IOError as e: + raise ESPLogTraceParserError("Failed to read log record args (%s)!" % e) + if len(trc_buf) < args_sz: + # print "EOF" + if len(trc_buf) > 0: + print "Unprocessed %d bytes of log record args!" % len(trc_buf) + # data_ok = False + break + try: + log_args = struct.unpack('<%sL' % nargs, trc_buf) + except struct.error as e: + raise ESPLogTraceParserError("Failed to unpack log record args (%s)!" % e) + # print log_args + recs.append(ESPLogTraceRecord(fmt_addr, list(log_args))) + + ftrc.close() + # sorted(recs, key=lambda rec: rec.fmt_addr) + return recs + + +def logtrace_get_str_from_elf(felf, str_addr): + tgt_str = "" + for sect in elfiter.sections(felf): + hdr = elfutil.section_hdr(felf, sect) + if hdr.sh_addr == 0 or hdr.sh_type != elfconst.SHT_PROGBITS: + continue + if str_addr < hdr.sh_addr or str_addr >= hdr.sh_addr + hdr.sh_size: + continue + # print "Found SECT: %x..%x @ %x" % (hdr.sh_addr, hdr.sh_addr + hdr.sh_size, str_addr - hdr.sh_addr) + sec_data = elfiter.getOnlyData(sect).contents + buf = cast(sec_data.d_buf, POINTER(c_char)) + for i in range(str_addr - hdr.sh_addr, hdr.sh_size): + if buf[i] == "\0": + break + tgt_str += buf[i] + if len(tgt_str) > 0: + return tgt_str + return None + +def logtrace_formated_print(recs, elfname, no_err): + try: + felf = elfutil.open_elf(elfname) + except OSError as e: + raise ESPLogTraceParserError("Failed to open ELF file (%s)!" % e) + + for lrec in recs: + fmt_str = logtrace_get_str_from_elf(felf, lrec.fmt_addr) + i = 0 + prcnt_idx = 0 + while i < len(lrec.args): + prcnt_idx = fmt_str.find('%', prcnt_idx, -2) # TODO: check str ending with % + if prcnt_idx == -1: + break + prcnt_idx += 1 # goto next char + if fmt_str[prcnt_idx] == 's': + # find string + arg_str = logtrace_get_str_from_elf(felf, lrec.args[i]) + if arg_str: + lrec.args[i] = arg_str + i += 1 + # print "\nFmt = {%s}, args = %d/%s" % lrec + fmt_str = fmt_str.replace('%p', '%x') + # print "=====> " + fmt_str % lrec.args + try: + print fmt_str % tuple(lrec.args), + # print ".", + pass + except Exception as e: + if not no_err: + print "Print error (%s)" % e + print "\nFmt = {%s}, args = %d/%s" % (fmt_str, len(lrec.args), lrec.args) + + elf.elf_end(felf) + +def main(): + + parser = argparse.ArgumentParser(description='ESP32 Log Trace Parsing Tool') + + parser.add_argument('trace_file', help='Path to log trace file', type=str) + parser.add_argument('elf_file', help='Path to program ELF file', type=str) + # parser.add_argument('--print-details', '-d', help='Print detailed stats', action='store_true') + parser.add_argument('--no-errors', '-n', help='Do not print errors', action='store_true') + args = parser.parse_args() + + # parse trace file + try: + print "Parse trace file '%s'..." % args.trace_file + lrecs = logtrace_parse(args.trace_file); + print "Parsing completed." + except ESPLogTraceParserError as e: + print "Failed to parse log trace (%s)!" % e + sys.exit(2) + # print recs + # get format strings and print info + print "====================================================================" + try: + logtrace_formated_print(lrecs, args.elf_file, args.no_errors); + except ESPLogTraceParserError as e: + print "Failed to print log trace (%s)!" % e + sys.exit(2) + print "\n====================================================================\n" + + print "Log records count: %d" % len(lrecs) + +if __name__ == '__main__': + main() diff --git a/tools/esp_app_trace/pylibelf/.gitignore b/tools/esp_app_trace/pylibelf/.gitignore new file mode 100644 index 000000000..42ac64781 --- /dev/null +++ b/tools/esp_app_trace/pylibelf/.gitignore @@ -0,0 +1,59 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +*.swp +*.swo +*.swn + diff --git a/tools/esp_app_trace/pylibelf/LICENSE b/tools/esp_app_trace/pylibelf/LICENSE new file mode 100644 index 000000000..2e216332f --- /dev/null +++ b/tools/esp_app_trace/pylibelf/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 d1m0 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/tools/esp_app_trace/pylibelf/README.md b/tools/esp_app_trace/pylibelf/README.md new file mode 100644 index 000000000..1019a8f32 --- /dev/null +++ b/tools/esp_app_trace/pylibelf/README.md @@ -0,0 +1,5 @@ +pylibelf +======== + +Python binding for libelf. + diff --git a/tools/esp_app_trace/pylibelf/__init__.py b/tools/esp_app_trace/pylibelf/__init__.py new file mode 100644 index 000000000..d00da18ab --- /dev/null +++ b/tools/esp_app_trace/pylibelf/__init__.py @@ -0,0 +1,155 @@ +from types import * +from constants import * +from ctypes import * + +lelf=CDLL("libelf.so.1") + +__all__ = [] + +all_objs = [] + +class ElfError(Exception): + def __init__(self, msg): + self.msg = msg + self.errno = elf_errno() + self.elfmsg = elf_errmsg(self.errno) + + def __str__(self): + return "ElfError(%d, %s): %s" % (self.errno, self.elfmsg, self.msg) + +__all__.append("ElfError") + +def nonNullDec(f): + def decorated(*args): + res = f(*args) + try: + a = res.contents + all_objs.append(res) + except ValueError: # NULL + raise ElfError(f.__name__ + " returned NULL") + return res + return decorated + +def nonNegDec(f): + def decorated(*args): + res = f(*args) + if 0 > res: + raise ElfError(f.__name__ + " returned %d" % (res,)) + return res + return decorated + +def badValDec(badVal): + def decorator(f): + def decorated(*args): + res = f(*args) + if res == badVal: + raise ElfError(f.__name__ + " returned %s" % (str(res),)) + return res + return decorated + return decorator + +def define(f, argtypes, restype, err_decorator = None): + f.argtypes = argtypes + f.restype = restype + name = f.__name__ + __all__.append(name) + + if (err_decorator != None): + f = err_decorator(f) + + globals()[name] = f + +define(lelf.elf_version, [ c_int ], c_int ) + +if (elf_version(EV_CURRENT) == EV_NONE): + raise Exception("Version mismatch") + +off_t = c_size_t # TODO(dbounov): Figure out actual off_t type + +define(lelf.elf_begin, [ c_int, Elf_Cmd, ElfP ], ElfP) +define(lelf.elf_getident, [ ElfP, POINTER(c_int) ], POINTER(Elf_IdentT), nonNullDec) +define(lelf.elf_end, [ ElfP ], c_int, nonNegDec ) +define(lelf.elf_cntl, [ ElfP, c_int ], c_int, nonNegDec) +define(lelf.elf_errmsg, [ c_int ], c_char_p) +define(lelf.elf_errno, [ ], c_int) +define(lelf.elf_fill, [ c_int ], None) +define(lelf.elf_flagdata, [ Elf_DataP, c_int, c_uint ], c_uint) +define(lelf.elf_flagehdr, [ ElfP, c_int, c_uint ], c_uint) +define(lelf.elf_flagelf, [ ElfP, c_int, c_uint ], c_uint) +define(lelf.elf_flagphdr, [ ElfP, c_int, c_uint ], c_uint) +define(lelf.elf_flagscn, [ Elf_ScnP, c_int, c_uint ], c_uint) +define(lelf.elf_flagshdr, [ Elf_ScnP, c_int, c_uint ], c_uint) +define(lelf.elf_getarhdr, [ ElfP ], POINTER(Elf_Arhdr)) +#define(lelf.elf_getarsym, [ ], ) +define(lelf.elf_getbase, [ ElfP ], off_t, nonNegDec) +define(lelf.elf_getdata, [ Elf_ScnP, Elf_DataP ], Elf_DataP) +define(lelf.elf_getscn, [ ElfP, c_size_t ], Elf_ScnP, nonNullDec ) +define(lelf.elf_getshnum, [ ElfP, POINTER(c_size_t) ], c_int, nonNegDec ) +define(lelf.elf_getshstrndx, [ ElfP, POINTER(c_size_t) ], c_int, nonNegDec ) +define(lelf.elf_hash, [ c_char_p ], c_ulong) +define(lelf.elf_kind, [ ElfP ], c_int ) +define(lelf.elf_memory, [ POINTER(c_char), c_size_t ], ElfP, nonNullDec) +define(lelf.elf_ndxscn, [ Elf_ScnP ], c_size_t, badValDec(SHN_UNDEF)) +define(lelf.elf_newdata, [ Elf_ScnP ], Elf_DataP, nonNullDec) +define(lelf.elf_newscn, [ ElfP ], Elf_ScnP, nonNullDec) +#define(lelf.elf_next, [ ], ) +define(lelf.elf_nextscn, [ ElfP, Elf_ScnP ], Elf_ScnP) +#define(lelf.elf_rand, [ ], ) +define(lelf.elf_rawdata, [ Elf_ScnP, Elf_DataP ], Elf_DataP) +#define(lelf.elf_rawfile, [ ], ) +define(lelf.elf_strptr, [ ElfP, c_size_t, c_size_t ], c_char_p) +define(lelf.elf_update, [ ElfP, c_int], off_t, nonNegDec) + +define(lelf.elf32_checksum, [ ElfP ], c_long) +define(lelf.elf32_fsize, [ c_int, c_size_t, c_uint ], c_size_t, nonNegDec) +define(lelf.elf32_getehdr, [ ElfP ], POINTER(Elf32_Ehdr), nonNullDec) +define(lelf.elf32_getphdr, [ ElfP ], POINTER(Elf32_Phdr), nonNullDec) +define(lelf.elf32_getshdr, [ Elf_ScnP ], POINTER(Elf32_Shdr), nonNullDec) +define(lelf.elf32_newehdr, [ ElfP ], POINTER(Elf32_Ehdr), nonNullDec) +define(lelf.elf32_newphdr, [ ElfP, c_size_t ], POINTER(Elf32_Phdr), nonNullDec) +define(lelf.elf32_xlatetof, [ Elf_DataP, Elf_DataP, c_uint ], Elf_DataP, nonNullDec) +define(lelf.elf32_xlatetom, [ Elf_DataP, Elf_DataP, c_uint ], Elf_DataP, nonNullDec) + + +define(lelf.elf64_checksum, [ ElfP ], c_long ) +define(lelf.elf64_fsize, [ c_int, c_size_t, c_uint ], c_size_t, nonNegDec) +define(lelf.elf64_getehdr,[ ElfP ], POINTER(Elf64_Ehdr), nonNullDec) +define(lelf.elf64_getphdr, [ ElfP ], POINTER(Elf64_Phdr), nonNullDec) +define(lelf.elf64_getshdr, [ Elf_ScnP ], POINTER(Elf64_Shdr), nonNullDec) +define(lelf.elf64_newehdr, [ ElfP ], POINTER(Elf64_Ehdr), nonNullDec) +define(lelf.elf64_newphdr, [ ElfP, c_size_t ], POINTER(Elf64_Phdr), nonNullDec) +define(lelf.elf64_xlatetof, [ Elf_DataP, Elf_DataP, c_uint ], Elf_DataP, nonNullDec) +define(lelf.elf64_xlatetom, [ Elf_DataP, Elf_DataP, c_uint ], Elf_DataP, nonNullDec) + +# NOTE(dbounov): Ignoring gelf functions for now + +#define(lelf.gelf_checksum, [ ], ) +#define(lelf.gelf_fsize, [ ], ) +#define(lelf.gelf_getcap, [ ], ) +#define(lelf.gelf_getclass, [ ], ) +#define(lelf.gelf_getdyn, [ ], ) +#define(lelf.gelf_getehdr, [ ], ) +#define(lelf.gelf_getmove, [ ], ) +#define(lelf.gelf_getphdr, [ ], ) +#define(lelf.gelf_getrel, [ ], ) +#define(lelf.gelf_getrela, [ ], ) +#define(lelf.gelf_getshdr, [ ], ) +#define(lelf.gelf_getsym, [ ], ) +#define(lelf.gelf_getsyminfo, [ ], ) +#define(lelf.gelf_getsymshndx, [ ], ) +#define(lelf.gelf_newehdr, [ ], ) +#define(lelf.gelf_newphdr, [ ], ) +#define(lelf.gelf_update_cap, [ ], ) +#define(lelf.gelf_update_dyn, [ ], ) +#define(lelf.gelf_update_ehdr, [ ], ) +#define(lelf.gelf_update_move, [ ], ) +#define(lelf.gelf_update_phdr, [ ], ) +#define(lelf.gelf_update_rel, [ ], ) +#define(lelf.gelf_update_rela, [ ], ) +#define(lelf.gelf_update_shdr, [ ], ) +#define(lelf.gelf_update_sym, [ ], ) +#define(lelf.gelf_update_symshndx, [ ], ) +#define(lelf.gelf_update_syminfo, [ ], ) +#define(lelf.gelf_xlatetof, [ ], ) +#define(lelf.gelf_xlatetom, [ ], ) +#define(lelf.nlist, [ ], ) diff --git a/tools/esp_app_trace/pylibelf/constants/__init__.py b/tools/esp_app_trace/pylibelf/constants/__init__.py new file mode 100644 index 000000000..890f97abb --- /dev/null +++ b/tools/esp_app_trace/pylibelf/constants/__init__.py @@ -0,0 +1,1850 @@ + +# Really simple expression types to handle arithmetic expressions referring +# to other # defines +class MacroExp: pass +class MacroRef(MacroExp): + def __init__(s, name): + s._name = name; + + def eval(s): + return lookup(s._name) + + def __add__(s, o): + return MacroAdd(s, o) + + def __radd__(s, o): + return MacroAdd(o, s) + +class MacroAdd(MacroExp): + def __init__(s, l, r): + s.l = l; + s.r = r; + + def eval(s): + l = s.l.eval() if (isinstance(s.l, MacroExp)) else s.l + r = s.r.eval() if (isinstance(s.r, MacroExp)) else s.r + + return l + r + + def __add__(s, o): + return MacroAdd(s, o) + + def __radd__(s, o): + return MacroAdd(o, s) + + +def lookup(n): + v = _consts[n] + if isinstance(v, MacroExp): + return v.eval() + else: + return v + +# Macro constants +_consts = { + "EI_NIDENT": 16 , # + "EI_MAG0": 0 , # File identification byte 0 index + "ELFMAG0": 0x7f , # Magic number byte 0 + "EI_MAG1": 1 , # File identification byte 1 index + "ELFMAG1": 'E' , # Magic number byte 1 + "EI_MAG2": 2 , # File identification byte 2 index + "ELFMAG2": 'L' , # Magic number byte 2 + "EI_MAG3": 3 , # File identification byte 3 index + "ELFMAG3": 'F' , # Magic number byte 3 + "ELFMAG": "\177ELF" , # + "SELFMAG": 4 , # + "EI_CLASS": 4 , # File class byte index + "ELFCLASSNONE": 0 , # Invalid class + "ELFCLASS32": 1 , # 32-bit objects + "ELFCLASS64": 2 , # 64-bit objects + "ELFCLASSNUM": 3 , # + "EI_DATA": 5 , # Data encoding byte index + "ELFDATANONE": 0 , # Invalid data encoding + "ELFDATA2LSB": 1 , # 2's complement, little endian + "ELFDATA2MSB": 2 , # 2's complement, big endian + "ELFDATANUM": 3 , # + "EI_VERSION": 6 , # File version byte index + "EI_OSABI": 7 , # OS ABI identification + "ELFOSABI_NONE": 0 , # UNIX System V ABI + "ELFOSABI_SYSV": 0 , # Alias. + "ELFOSABI_HPUX": 1 , # HP-UX + "ELFOSABI_NETBSD": 2 , # NetBSD. + "ELFOSABI_GNU": 3 , # Object uses GNU ELF extensions. + "ELFOSABI_LINUX": MacroRef("ELFOSABI_GNU") , # Compatibility alias. + "ELFOSABI_SOLARIS": 6 , # Sun Solaris. + "ELFOSABI_AIX": 7 , # IBM AIX. + "ELFOSABI_IRIX": 8 , # SGI Irix. + "ELFOSABI_FREEBSD": 9 , # FreeBSD. + "ELFOSABI_TRU64": 10 , # Compaq TRU64 UNIX. + "ELFOSABI_MODESTO": 11 , # Novell Modesto. + "ELFOSABI_OPENBSD": 12 , # OpenBSD. + "ELFOSABI_ARM_AEABI": 64 , # ARM EABI + "ELFOSABI_ARM": 97 , # ARM + "ELFOSABI_STANDALONE": 255 , # Standalone (embedded) application + "EI_ABIVERSION": 8 , # ABI version + "EI_PAD": 9 , # Byte index of padding bytes + "ET_NONE": 0 , # No file type + "ET_REL": 1 , # Relocatable file + "ET_EXEC": 2 , # Executable file + "ET_DYN": 3 , # Shared object file + "ET_CORE": 4 , # Core file + "ET_NUM": 5 , # Number of defined types + "ET_LOOS": 0xfe00 , # OS-specific range start + "ET_HIOS": 0xfeff , # OS-specific range end + "ET_LOPROC": 0xff00 , # Processor-specific range start + "ET_HIPROC": 0xffff , # Processor-specific range end + "EM_NONE": 0 , # No machine + "EM_M32": 1 , # AT&T WE 32100 + "EM_SPARC": 2 , # SUN SPARC + "EM_386": 3 , # Intel 80386 + "EM_68K": 4 , # Motorola m68k family + "EM_88K": 5 , # Motorola m88k family + "EM_860": 7 , # Intel 80860 + "EM_MIPS": 8 , # MIPS R3000 big-endian + "EM_S370": 9 , # IBM System/370 + "EM_MIPS_RS3_LE": 10 , # MIPS R3000 little-endian + "EM_PARISC": 15 , # HPPA + "EM_VPP500": 17 , # Fujitsu VPP500 + "EM_SPARC32PLUS": 18 , # Sun's "v8plus" + "EM_960": 19 , # Intel 80960 + "EM_PPC": 20 , # PowerPC + "EM_PPC64": 21 , # PowerPC 64-bit + "EM_S390": 22 , # IBM S390 + "EM_V800": 36 , # NEC V800 series + "EM_FR20": 37 , # Fujitsu FR20 + "EM_RH32": 38 , # TRW RH-32 + "EM_RCE": 39 , # Motorola RCE + "EM_ARM": 40 , # ARM + "EM_FAKE_ALPHA": 41 , # Digital Alpha + "EM_SH": 42 , # Hitachi SH + "EM_SPARCV9": 43 , # SPARC v9 64-bit + "EM_TRICORE": 44 , # Siemens Tricore + "EM_ARC": 45 , # Argonaut RISC Core + "EM_H8_300": 46 , # Hitachi H8/300 + "EM_H8_300H": 47 , # Hitachi H8/300H + "EM_H8S": 48 , # Hitachi H8S + "EM_H8_500": 49 , # Hitachi H8/500 + "EM_IA_64": 50 , # Intel Merced + "EM_MIPS_X": 51 , # Stanford MIPS-X + "EM_COLDFIRE": 52 , # Motorola Coldfire + "EM_68HC12": 53 , # Motorola M68HC12 + "EM_MMA": 54 , # Fujitsu MMA Multimedia Accelerator + "EM_PCP": 55 , # Siemens PCP + "EM_NCPU": 56 , # Sony nCPU embeeded RISC + "EM_NDR1": 57 , # Denso NDR1 microprocessor + "EM_STARCORE": 58 , # Motorola Start*Core processor + "EM_ME16": 59 , # Toyota ME16 processor + "EM_ST100": 60 , # STMicroelectronic ST100 processor + "EM_TINYJ": 61 , # Advanced Logic Corp. Tinyj emb.fam + "EM_X86_64": 62 , # AMD x86-64 architecture + "EM_PDSP": 63 , # Sony DSP Processor + "EM_FX66": 66 , # Siemens FX66 microcontroller + "EM_ST9PLUS": 67 , # STMicroelectronics ST9+ 8/16 mc + "EM_ST7": 68 , # STmicroelectronics ST7 8 bit mc + "EM_68HC16": 69 , # Motorola MC68HC16 microcontroller + "EM_68HC11": 70 , # Motorola MC68HC11 microcontroller + "EM_68HC08": 71 , # Motorola MC68HC08 microcontroller + "EM_68HC05": 72 , # Motorola MC68HC05 microcontroller + "EM_SVX": 73 , # Silicon Graphics SVx + "EM_ST19": 74 , # STMicroelectronics ST19 8 bit mc + "EM_VAX": 75 , # Digital VAX + "EM_CRIS": 76 , # Axis Communications 32-bit embedded processor + "EM_JAVELIN": 77 , # Infineon Technologies 32-bit embedded processor + "EM_FIREPATH": 78 , # Element 14 64-bit DSP Processor + "EM_ZSP": 79 , # LSI Logic 16-bit DSP Processor + "EM_MMIX": 80 , # Donald Knuth's educational 64-bit processor + "EM_HUANY": 81 , # Harvard University machine-independent object files + "EM_PRISM": 82 , # SiTera Prism + "EM_AVR": 83 , # Atmel AVR 8-bit microcontroller + "EM_FR30": 84 , # Fujitsu FR30 + "EM_D10V": 85 , # Mitsubishi D10V + "EM_D30V": 86 , # Mitsubishi D30V + "EM_V850": 87 , # NEC v850 + "EM_M32R": 88 , # Mitsubishi M32R + "EM_MN10300": 89 , # Matsushita MN10300 + "EM_MN10200": 90 , # Matsushita MN10200 + "EM_PJ": 91 , # picoJava + "EM_OPENRISC": 92 , # OpenRISC 32-bit embedded processor + "EM_ARC_A5": 93 , # ARC Cores Tangent-A5 + "EM_XTENSA": 94 , # Tensilica Xtensa Architecture + "EM_NUM": 95 , # + "EM_ALPHA": 0x9026 , # + "EV_NONE": 0 , # Invalid ELF version + "EV_CURRENT": 1 , # Current version + "EV_NUM": 2 , # + "SHN_UNDEF": 0 , # Undefined section + "SHN_LORESERVE": 0xff00 , # Start of reserved indices + "SHN_LOPROC": 0xff00 , # Start of processor-specific + "SHN_BEFORE": 0xff00 , # Order section before all others + "SHN_AFTER": 0xff01 , # Order section after all others + "SHN_HIPROC": 0xff1f , # End of processor-specific + "SHN_LOOS": 0xff20 , # Start of OS-specific + "SHN_HIOS": 0xff3f , # End of OS-specific + "SHN_ABS": 0xfff1 , # Associated symbol is absolute + "SHN_COMMON": 0xfff2 , # Associated symbol is common + "SHN_XINDEX": 0xffff , # Index is in extra table. + "SHN_HIRESERVE": 0xffff , # End of reserved indices + "SHT_NULL": 0 , # Section header table entry unused + "SHT_PROGBITS": 1 , # Program data + "SHT_SYMTAB": 2 , # Symbol table + "SHT_STRTAB": 3 , # String table + "SHT_RELA": 4 , # Relocation entries with addends + "SHT_HASH": 5 , # Symbol hash table + "SHT_DYNAMIC": 6 , # Dynamic linking information + "SHT_NOTE": 7 , # Notes + "SHT_NOBITS": 8 , # Program space with no data (bss) + "SHT_REL": 9 , # Relocation entries, no addends + "SHT_SHLIB": 10 , # Reserved + "SHT_DYNSYM": 11 , # Dynamic linker symbol table + "SHT_INIT_ARRAY": 14 , # Array of constructors + "SHT_FINI_ARRAY": 15 , # Array of destructors + "SHT_PREINIT_ARRAY": 16 , # Array of pre-constructors + "SHT_GROUP": 17 , # Section group + "SHT_SYMTAB_SHNDX": 18 , # Extended section indeces + "SHT_NUM": 19 , # Number of defined types. + "SHT_LOOS": 0x60000000 , # Start OS-specific. + "SHT_GNU_ATTRIBUTES": 0x6ffffff5 , # Object attributes. + "SHT_GNU_HASH": 0x6ffffff6 , # GNU-style hash table. + "SHT_GNU_LIBLIST": 0x6ffffff7 , # Prelink library list + "SHT_CHECKSUM": 0x6ffffff8 , # Checksum for DSO content. + "SHT_LOSUNW": 0x6ffffffa , # Sun-specific low bound. + "SHT_SUNW_move": 0x6ffffffa , # + "SHT_SUNW_COMDAT": 0x6ffffffb , # + "SHT_SUNW_syminfo": 0x6ffffffc , # + "SHT_GNU_verdef": 0x6ffffffd , # Version definition section. + "SHT_GNU_verneed": 0x6ffffffe , # Version needs section. + "SHT_GNU_versym": 0x6fffffff , # Version symbol table. + "SHT_HISUNW": 0x6fffffff , # Sun-specific high bound. + "SHT_HIOS": 0x6fffffff , # End OS-specific type + "SHT_LOPROC": 0x70000000 , # Start of processor-specific + "SHT_HIPROC": 0x7fffffff , # End of processor-specific + "SHT_LOUSER": 0x80000000 , # Start of application-specific + "SHT_HIUSER": 0x8fffffff , # End of application-specific + "SHF_MASKOS": 0x0ff00000 , # OS-specific. + "SHF_MASKPROC": 0xf0000000 , # Processor-specific + "SHF_ORDERED": (1 << 30) , # Special ordering requirement + "SHF_EXCLUDE": (1 << 31) , # Section is excluded unless + "GRP_COMDAT": 0x1 , # Mark group as COMDAT. + "SYMINFO_BT_SELF": 0xffff , # Symbol bound to self + "SYMINFO_BT_PARENT": 0xfffe , # Symbol bound to parent + "SYMINFO_BT_LOWRESERVE": 0xff00 , # Beginning of reserved entries + "SYMINFO_FLG_DIRECT": 0x0001 , # Direct bound symbol + "SYMINFO_FLG_PASSTHRU": 0x0002 , # Pass-thru symbol for translator + "SYMINFO_FLG_COPY": 0x0004 , # Symbol is a copy-reloc + "SYMINFO_FLG_LAZYLOAD": 0x0008 , # Symbol bound to object to be lazy + "SYMINFO_NONE": 0 , # + "SYMINFO_CURRENT": 1 , # + "SYMINFO_NUM": 2 , # + "STB_LOCAL": 0 , # Local symbol + "STB_GLOBAL": 1 , # Global symbol + "STB_WEAK": 2 , # Weak symbol + "STB_NUM": 3 , # Number of defined types. + "STB_LOOS": 10 , # Start of OS-specific + "STB_GNU_UNIQUE": 10 , # Unique symbol. + "STB_HIOS": 12 , # End of OS-specific + "STB_LOPROC": 13 , # Start of processor-specific + "STB_HIPROC": 15 , # End of processor-specific + "STT_NOTYPE": 0 , # Symbol type is unspecified + "STT_OBJECT": 1 , # Symbol is a data object + "STT_FUNC": 2 , # Symbol is a code object + "STT_SECTION": 3 , # Symbol associated with a section + "STT_FILE": 4 , # Symbol's name is file name + "STT_COMMON": 5 , # Symbol is a common data object + "STT_TLS": 6 , # Symbol is thread-local data object + "STT_NUM": 7 , # Number of defined types. + "STT_LOOS": 10 , # Start of OS-specific + "STT_GNU_IFUNC": 10 , # Symbol is indirect code object + "STT_HIOS": 12 , # End of OS-specific + "STT_LOPROC": 13 , # Start of processor-specific + "STT_HIPROC": 15 , # End of processor-specific + "STN_UNDEF": 0 , # End of a chain. + "STV_DEFAULT": 0 , # Default symbol visibility rules + "STV_INTERNAL": 1 , # Processor specific hidden class + "STV_HIDDEN": 2 , # Sym unavailable in other modules + "STV_PROTECTED": 3 , # Not preemptible, not exported + "PN_XNUM": 0xffff , # + "PT_NULL": 0 , # Program header table entry unused + "PT_LOAD": 1 , # Loadable program segment + "PT_DYNAMIC": 2 , # Dynamic linking information + "PT_INTERP": 3 , # Program interpreter + "PT_NOTE": 4 , # Auxiliary information + "PT_SHLIB": 5 , # Reserved + "PT_PHDR": 6 , # Entry for header table itself + "PT_TLS": 7 , # Thread-local storage segment + "PT_NUM": 8 , # Number of defined types + "PT_LOOS": 0x60000000 , # Start of OS-specific + "PT_GNU_EH_FRAME": 0x6474e550 , # GCC .eh_frame_hdr segment + "PT_GNU_STACK": 0x6474e551 , # Indicates stack executability + "PT_GNU_RELRO": 0x6474e552 , # Read-only after relocation + "PT_LOSUNW": 0x6ffffffa , # + "PT_SUNWBSS": 0x6ffffffa , # Sun Specific segment + "PT_SUNWSTACK": 0x6ffffffb , # Stack segment + "PT_HISUNW": 0x6fffffff , # + "PT_HIOS": 0x6fffffff , # End of OS-specific + "PT_LOPROC": 0x70000000 , # Start of processor-specific + "PT_HIPROC": 0x7fffffff , # End of processor-specific + "PF_X": (1 << 0) , # Segment is executable + "PF_W": (1 << 1) , # Segment is writable + "PF_R": (1 << 2) , # Segment is readable + "PF_MASKOS": 0x0ff00000 , # OS-specific + "PF_MASKPROC": 0xf0000000 , # Processor-specific + "NT_PRSTATUS": 1 , # Contains copy of prstatus struct + "NT_FPREGSET": 2 , # Contains copy of fpregset struct + "NT_PRPSINFO": 3 , # Contains copy of prpsinfo struct + "NT_PRXREG": 4 , # Contains copy of prxregset struct + "NT_TASKSTRUCT": 4 , # Contains copy of task structure + "NT_PLATFORM": 5 , # String from sysinfo(SI_PLATFORM) + "NT_AUXV": 6 , # Contains copy of auxv array + "NT_GWINDOWS": 7 , # Contains copy of gwindows struct + "NT_ASRS": 8 , # Contains copy of asrset struct + "NT_PSTATUS": 10 , # Contains copy of pstatus struct + "NT_PSINFO": 13 , # Contains copy of psinfo struct + "NT_PRCRED": 14 , # Contains copy of prcred struct + "NT_UTSNAME": 15 , # Contains copy of utsname struct + "NT_LWPSTATUS": 16 , # Contains copy of lwpstatus struct + "NT_LWPSINFO": 17 , # Contains copy of lwpinfo struct + "NT_PRFPXREG": 20 , # Contains copy of fprxregset struct + "NT_PRXFPREG": 0x46e62b7f , # Contains copy of user_fxsr_struct + "NT_PPC_VMX": 0x100 , # PowerPC Altivec/VMX registers + "NT_PPC_SPE": 0x101 , # PowerPC SPE/EVR registers + "NT_PPC_VSX": 0x102 , # PowerPC VSX registers + "NT_386_TLS": 0x200 , # i386 TLS slots (struct user_desc) + "NT_386_IOPERM": 0x201 , # x86 io permission bitmap (1=deny) + "NT_X86_XSTATE": 0x202 , # x86 extended state using xsave + "NT_VERSION": 1 , # Contains a version string. + "DT_NULL": 0 , # Marks end of dynamic section + "DT_NEEDED": 1 , # Name of needed library + "DT_PLTRELSZ": 2 , # Size in bytes of PLT relocs + "DT_PLTGOT": 3 , # Processor defined value + "DT_HASH": 4 , # Address of symbol hash table + "DT_STRTAB": 5 , # Address of string table + "DT_SYMTAB": 6 , # Address of symbol table + "DT_RELA": 7 , # Address of Rela relocs + "DT_RELASZ": 8 , # Total size of Rela relocs + "DT_RELAENT": 9 , # Size of one Rela reloc + "DT_STRSZ": 10 , # Size of string table + "DT_SYMENT": 11 , # Size of one symbol table entry + "DT_INIT": 12 , # Address of init function + "DT_FINI": 13 , # Address of termination function + "DT_SONAME": 14 , # Name of shared object + "DT_RPATH": 15 , # Library search path (deprecated) + "DT_SYMBOLIC": 16 , # Start symbol search here + "DT_REL": 17 , # Address of Rel relocs + "DT_RELSZ": 18 , # Total size of Rel relocs + "DT_RELENT": 19 , # Size of one Rel reloc + "DT_PLTREL": 20 , # Type of reloc in PLT + "DT_DEBUG": 21 , # For debugging; unspecified + "DT_TEXTREL": 22 , # Reloc might modify .text + "DT_JMPREL": 23 , # Address of PLT relocs + "DT_BIND_NOW": 24 , # Process relocations of object + "DT_INIT_ARRAY": 25 , # Array with addresses of init fct + "DT_FINI_ARRAY": 26 , # Array with addresses of fini fct + "DT_INIT_ARRAYSZ": 27 , # Size in bytes of DT_INIT_ARRAY + "DT_FINI_ARRAYSZ": 28 , # Size in bytes of DT_FINI_ARRAY + "DT_RUNPATH": 29 , # Library search path + "DT_FLAGS": 30 , # Flags for the object being loaded + "DT_ENCODING": 32 , # Start of encoded range + "DT_PREINIT_ARRAY": 32 , # Array with addresses of preinit fct + "DT_PREINIT_ARRAYSZ": 33 , # size in bytes of DT_PREINIT_ARRAY + "DT_NUM": 34 , # Number used + "DT_LOOS": 0x6000000d , # Start of OS-specific + "DT_HIOS": 0x6ffff000 , # End of OS-specific + "DT_LOPROC": 0x70000000 , # Start of processor-specific + "DT_HIPROC": 0x7fffffff , # End of processor-specific + "DT_PROCNUM": MacroRef("DT_MIPS_NUM") , # Most used by any processor + "DT_VALRNGLO": 0x6ffffd00 , # + "DT_GNU_PRELINKED": 0x6ffffdf5 , # Prelinking timestamp + "DT_GNU_CONFLICTSZ": 0x6ffffdf6 , # Size of conflict section + "DT_GNU_LIBLISTSZ": 0x6ffffdf7 , # Size of library list + "DT_CHECKSUM": 0x6ffffdf8 , # + "DT_PLTPADSZ": 0x6ffffdf9 , # + "DT_MOVEENT": 0x6ffffdfa , # + "DT_MOVESZ": 0x6ffffdfb , # + "DT_FEATURE_1": 0x6ffffdfc , # Feature selection (DTF_*). + "DT_POSFLAG_1": 0x6ffffdfd , # Flags for DT_* entries, effecting + "DT_SYMINSZ": 0x6ffffdfe , # Size of syminfo table (in bytes) + "DT_SYMINENT": 0x6ffffdff , # Entry size of syminfo + "DT_VALRNGHI": 0x6ffffdff , # + "DT_VALNUM": 12 , # + "DT_ADDRRNGLO": 0x6ffffe00 , # + "DT_GNU_HASH": 0x6ffffef5 , # GNU-style hash table. + "DT_TLSDESC_PLT": 0x6ffffef6 , # + "DT_TLSDESC_GOT": 0x6ffffef7 , # + "DT_GNU_CONFLICT": 0x6ffffef8 , # Start of conflict section + "DT_GNU_LIBLIST": 0x6ffffef9 , # Library list + "DT_CONFIG": 0x6ffffefa , # Configuration information. + "DT_DEPAUDIT": 0x6ffffefb , # Dependency auditing. + "DT_AUDIT": 0x6ffffefc , # Object auditing. + "DT_PLTPAD": 0x6ffffefd , # PLT padding. + "DT_MOVETAB": 0x6ffffefe , # Move table. + "DT_SYMINFO": 0x6ffffeff , # Syminfo table. + "DT_ADDRRNGHI": 0x6ffffeff , # + "DT_ADDRNUM": 11 , # + "DT_VERSYM": 0x6ffffff0 , # + "DT_RELACOUNT": 0x6ffffff9 , # + "DT_RELCOUNT": 0x6ffffffa , # + "DT_FLAGS_1": 0x6ffffffb , # State flags, see DF_1_* below. + "DT_VERDEF": 0x6ffffffc , # Address of version definition + "DT_VERDEFNUM": 0x6ffffffd , # Number of version definitions + "DT_VERNEED": 0x6ffffffe , # Address of table with needed + "DT_VERNEEDNUM": 0x6fffffff , # Number of needed versions + "DT_VERSIONTAGNUM": 16 , # + "DT_AUXILIARY": 0x7ffffffd , # Shared object to load before self + "DT_FILTER": 0x7fffffff , # Shared object to get values from + "DT_EXTRANUM": 3 , # + "DF_ORIGIN": 0x00000001 , # Object may use DF_ORIGIN + "DF_SYMBOLIC": 0x00000002 , # Symbol resolutions starts here + "DF_TEXTREL": 0x00000004 , # Object contains text relocations + "DF_BIND_NOW": 0x00000008 , # No lazy binding for this object + "DF_STATIC_TLS": 0x00000010 , # Module uses the static TLS model + "DF_1_NOW": 0x00000001 , # Set RTLD_NOW for this object. + "DF_1_GLOBAL": 0x00000002 , # Set RTLD_GLOBAL for this object. + "DF_1_GROUP": 0x00000004 , # Set RTLD_GROUP for this object. + "DF_1_NODELETE": 0x00000008 , # Set RTLD_NODELETE for this object. + "DF_1_LOADFLTR": 0x00000010 , # Trigger filtee loading at runtime. + "DF_1_INITFIRST": 0x00000020 , # Set RTLD_INITFIRST for this object + "DF_1_NOOPEN": 0x00000040 , # Set RTLD_NOOPEN for this object. + "DF_1_ORIGIN": 0x00000080 , # $ORIGIN must be handled. + "DF_1_DIRECT": 0x00000100 , # Direct binding enabled. + "DF_1_TRANS": 0x00000200 , # + "DF_1_INTERPOSE": 0x00000400 , # Object is used to interpose. + "DF_1_NODEFLIB": 0x00000800 , # Ignore default lib search path. + "DF_1_NODUMP": 0x00001000 , # Object can't be dldump'ed. + "DF_1_CONFALT": 0x00002000 , # Configuration alternative created. + "DF_1_ENDFILTEE": 0x00004000 , # Filtee terminates filters search. + "DF_1_DISPRELDNE": 0x00008000 , # Disp reloc applied at build time. + "DF_1_DISPRELPND": 0x00010000 , # Disp reloc applied at run-time. + "DTF_1_PARINIT": 0x00000001 , # + "DTF_1_CONFEXP": 0x00000002 , # + "DF_P1_LAZYLOAD": 0x00000001 , # Lazyload following object. + "DF_P1_GROUPPERM": 0x00000002 , # Symbols from next object are not + "VER_DEF_NONE": 0 , # No version + "VER_DEF_CURRENT": 1 , # Current version + "VER_DEF_NUM": 2 , # Given version number + "VER_FLG_BASE": 0x1 , # Version definition of file itself + "VER_FLG_WEAK": 0x2 , # Weak version identifier + "VER_NDX_LOCAL": 0 , # Symbol is local. + "VER_NDX_GLOBAL": 1 , # Symbol is global. + "VER_NDX_LORESERVE": 0xff00 , # Beginning of reserved entries. + "VER_NDX_ELIMINATE": 0xff01 , # Symbol is to be eliminated. + "VER_NEED_NONE": 0 , # No version + "VER_NEED_CURRENT": 1 , # Current version + "VER_NEED_NUM": 2 , # Given version number + "VER_FLG_WEAK": 0x2 , # Weak version identifier + "AT_NULL": 0 , # End of vector + "AT_IGNORE": 1 , # Entry should be ignored + "AT_EXECFD": 2 , # File descriptor of program + "AT_PHDR": 3 , # Program headers for program + "AT_PHENT": 4 , # Size of program header entry + "AT_PHNUM": 5 , # Number of program headers + "AT_PAGESZ": 6 , # System page size + "AT_BASE": 7 , # Base address of interpreter + "AT_FLAGS": 8 , # Flags + "AT_ENTRY": 9 , # Entry point of program + "AT_NOTELF": 10 , # Program is not ELF + "AT_UID": 11 , # Real uid + "AT_EUID": 12 , # Effective uid + "AT_GID": 13 , # Real gid + "AT_EGID": 14 , # Effective gid + "AT_CLKTCK": 17 , # Frequency of times() + "AT_PLATFORM": 15 , # String identifying platform. + "AT_HWCAP": 16 , # Machine dependent hints about + "AT_FPUCW": 18 , # Used FPU control word. + "AT_DCACHEBSIZE": 19 , # Data cache block size. + "AT_ICACHEBSIZE": 20 , # Instruction cache block size. + "AT_UCACHEBSIZE": 21 , # Unified cache block size. + "AT_IGNOREPPC": 22 , # Entry should be ignored. + "AT_SECURE": 23 , # Boolean, was exec setuid-like? + "AT_BASE_PLATFORM": 24 , # String identifying real platforms. + "AT_RANDOM": 25 , # Address of 16 random bytes. + "AT_EXECFN": 31 , # Filename of executable. + "AT_SYSINFO": 32 , # + "AT_SYSINFO_EHDR": 33 , # + "AT_L1I_CACHESHAPE": 34 , # + "AT_L1D_CACHESHAPE": 35 , # + "AT_L2_CACHESHAPE": 36 , # + "AT_L3_CACHESHAPE": 37 , # + "ELF_NOTE_SOLARIS": "SUNW Solaris" , # + "ELF_NOTE_GNU": "GNU" , # + "ELF_NOTE_PAGESIZE_HINT": 1 , # + "NT_GNU_ABI_TAG": 1 , # + "ELF_NOTE_ABI": MacroRef("NT_GNU_ABI_TAG") , # Old name. + "ELF_NOTE_OS_LINUX": 0 , # + "ELF_NOTE_OS_GNU": 1 , # + "ELF_NOTE_OS_SOLARIS2": 2 , # + "ELF_NOTE_OS_FREEBSD": 3 , # + "NT_GNU_HWCAP": 2 , # + "NT_GNU_BUILD_ID": 3 , # + "NT_GNU_GOLD_VERSION": 4 , # + "EF_CPU32": 0x00810000 , # + "R_68K_NONE": 0 , # No reloc + "R_68K_32": 1 , # Direct 32 bit + "R_68K_16": 2 , # Direct 16 bit + "R_68K_8": 3 , # Direct 8 bit + "R_68K_PC32": 4 , # PC relative 32 bit + "R_68K_PC16": 5 , # PC relative 16 bit + "R_68K_PC8": 6 , # PC relative 8 bit + "R_68K_GOT32": 7 , # 32 bit PC relative GOT entry + "R_68K_GOT16": 8 , # 16 bit PC relative GOT entry + "R_68K_GOT8": 9 , # 8 bit PC relative GOT entry + "R_68K_GOT32O": 10 , # 32 bit GOT offset + "R_68K_GOT16O": 11 , # 16 bit GOT offset + "R_68K_GOT8O": 12 , # 8 bit GOT offset + "R_68K_PLT32": 13 , # 32 bit PC relative PLT address + "R_68K_PLT16": 14 , # 16 bit PC relative PLT address + "R_68K_PLT8": 15 , # 8 bit PC relative PLT address + "R_68K_PLT32O": 16 , # 32 bit PLT offset + "R_68K_PLT16O": 17 , # 16 bit PLT offset + "R_68K_PLT8O": 18 , # 8 bit PLT offset + "R_68K_COPY": 19 , # Copy symbol at runtime + "R_68K_GLOB_DAT": 20 , # Create GOT entry + "R_68K_JMP_SLOT": 21 , # Create PLT entry + "R_68K_RELATIVE": 22 , # Adjust by program base + "R_68K_TLS_GD32": 25 , # 32 bit GOT offset for GD + "R_68K_TLS_GD16": 26 , # 16 bit GOT offset for GD + "R_68K_TLS_GD8": 27 , # 8 bit GOT offset for GD + "R_68K_TLS_LDM32": 28 , # 32 bit GOT offset for LDM + "R_68K_TLS_LDM16": 29 , # 16 bit GOT offset for LDM + "R_68K_TLS_LDM8": 30 , # 8 bit GOT offset for LDM + "R_68K_TLS_LDO32": 31 , # 32 bit module-relative offset + "R_68K_TLS_LDO16": 32 , # 16 bit module-relative offset + "R_68K_TLS_LDO8": 33 , # 8 bit module-relative offset + "R_68K_TLS_IE32": 34 , # 32 bit GOT offset for IE + "R_68K_TLS_IE16": 35 , # 16 bit GOT offset for IE + "R_68K_TLS_IE8": 36 , # 8 bit GOT offset for IE + "R_68K_TLS_LE32": 37 , # 32 bit offset relative to + "R_68K_TLS_LE16": 38 , # 16 bit offset relative to + "R_68K_TLS_LE8": 39 , # 8 bit offset relative to + "R_68K_TLS_DTPMOD32": 40 , # 32 bit module number + "R_68K_TLS_DTPREL32": 41 , # 32 bit module-relative offset + "R_68K_TLS_TPREL32": 42 , # 32 bit TP-relative offset + "R_68K_NUM": 43 , # + "R_386_NONE": 0 , # No reloc + "R_386_32": 1 , # Direct 32 bit + "R_386_PC32": 2 , # PC relative 32 bit + "R_386_GOT32": 3 , # 32 bit GOT entry + "R_386_PLT32": 4 , # 32 bit PLT address + "R_386_COPY": 5 , # Copy symbol at runtime + "R_386_GLOB_DAT": 6 , # Create GOT entry + "R_386_JMP_SLOT": 7 , # Create PLT entry + "R_386_RELATIVE": 8 , # Adjust by program base + "R_386_GOTOFF": 9 , # 32 bit offset to GOT + "R_386_GOTPC": 10 , # 32 bit PC relative offset to GOT + "R_386_32PLT": 11 , # + "R_386_TLS_TPOFF": 14 , # Offset in static TLS block + "R_386_TLS_IE": 15 , # Address of GOT entry for static TLS + "R_386_TLS_GOTIE": 16 , # GOT entry for static TLS block + "R_386_TLS_LE": 17 , # Offset relative to static TLS + "R_386_TLS_GD": 18 , # Direct 32 bit for GNU version of + "R_386_TLS_LDM": 19 , # Direct 32 bit for GNU version of + "R_386_16": 20 , # + "R_386_PC16": 21 , # + "R_386_8": 22 , # + "R_386_PC8": 23 , # + "R_386_TLS_GD_32": 24 , # Direct 32 bit for general dynamic + "R_386_TLS_GD_PUSH": 25 , # Tag for pushl in GD TLS code + "R_386_TLS_GD_CALL": 26 , # Relocation for call to + "R_386_TLS_GD_POP": 27 , # Tag for popl in GD TLS code + "R_386_TLS_LDM_32": 28 , # Direct 32 bit for local dynamic + "R_386_TLS_LDM_PUSH": 29 , # Tag for pushl in LDM TLS code + "R_386_TLS_LDM_CALL": 30 , # Relocation for call to + "R_386_TLS_LDM_POP": 31 , # Tag for popl in LDM TLS code + "R_386_TLS_LDO_32": 32 , # Offset relative to TLS block + "R_386_TLS_IE_32": 33 , # GOT entry for negated static TLS + "R_386_TLS_LE_32": 34 , # Negated offset relative to static + "R_386_TLS_DTPMOD32": 35 , # ID of module containing symbol + "R_386_TLS_DTPOFF32": 36 , # Offset in TLS block + "R_386_TLS_TPOFF32": 37 , # Negated offset in static TLS block + "R_386_TLS_GOTDESC": 39 , # GOT offset for TLS descriptor. + "R_386_TLS_DESC_CALL": 40 , # Marker of call through TLS + "R_386_TLS_DESC": 41 , # TLS descriptor containing + "R_386_IRELATIVE": 42 , # Adjust indirectly by program base + "R_386_NUM": 43 , # + "STT_SPARC_REGISTER": 13 , # Global register reserved to app. + "EF_SPARCV9_MM": 3 , # + "EF_SPARCV9_TSO": 0 , # + "EF_SPARCV9_PSO": 1 , # + "EF_SPARCV9_RMO": 2 , # + "EF_SPARC_LEDATA": 0x800000 , # little endian data + "EF_SPARC_EXT_MASK": 0xFFFF00 , # + "EF_SPARC_32PLUS": 0x000100 , # generic V8+ features + "EF_SPARC_SUN_US1": 0x000200 , # Sun UltraSPARC1 extensions + "EF_SPARC_HAL_R1": 0x000400 , # HAL R1 extensions + "EF_SPARC_SUN_US3": 0x000800 , # Sun UltraSPARCIII extensions + "R_SPARC_NONE": 0 , # No reloc + "R_SPARC_8": 1 , # Direct 8 bit + "R_SPARC_16": 2 , # Direct 16 bit + "R_SPARC_32": 3 , # Direct 32 bit + "R_SPARC_DISP8": 4 , # PC relative 8 bit + "R_SPARC_DISP16": 5 , # PC relative 16 bit + "R_SPARC_DISP32": 6 , # PC relative 32 bit + "R_SPARC_WDISP30": 7 , # PC relative 30 bit shifted + "R_SPARC_WDISP22": 8 , # PC relative 22 bit shifted + "R_SPARC_HI22": 9 , # High 22 bit + "R_SPARC_22": 10 , # Direct 22 bit + "R_SPARC_13": 11 , # Direct 13 bit + "R_SPARC_LO10": 12 , # Truncated 10 bit + "R_SPARC_GOT10": 13 , # Truncated 10 bit GOT entry + "R_SPARC_GOT13": 14 , # 13 bit GOT entry + "R_SPARC_GOT22": 15 , # 22 bit GOT entry shifted + "R_SPARC_PC10": 16 , # PC relative 10 bit truncated + "R_SPARC_PC22": 17 , # PC relative 22 bit shifted + "R_SPARC_WPLT30": 18 , # 30 bit PC relative PLT address + "R_SPARC_COPY": 19 , # Copy symbol at runtime + "R_SPARC_GLOB_DAT": 20 , # Create GOT entry + "R_SPARC_JMP_SLOT": 21 , # Create PLT entry + "R_SPARC_RELATIVE": 22 , # Adjust by program base + "R_SPARC_UA32": 23 , # Direct 32 bit unaligned + "R_SPARC_PLT32": 24 , # Direct 32 bit ref to PLT entry + "R_SPARC_HIPLT22": 25 , # High 22 bit PLT entry + "R_SPARC_LOPLT10": 26 , # Truncated 10 bit PLT entry + "R_SPARC_PCPLT32": 27 , # PC rel 32 bit ref to PLT entry + "R_SPARC_PCPLT22": 28 , # PC rel high 22 bit PLT entry + "R_SPARC_PCPLT10": 29 , # PC rel trunc 10 bit PLT entry + "R_SPARC_10": 30 , # Direct 10 bit + "R_SPARC_11": 31 , # Direct 11 bit + "R_SPARC_64": 32 , # Direct 64 bit + "R_SPARC_OLO10": 33 , # 10bit with secondary 13bit addend + "R_SPARC_HH22": 34 , # Top 22 bits of direct 64 bit + "R_SPARC_HM10": 35 , # High middle 10 bits of ... + "R_SPARC_LM22": 36 , # Low middle 22 bits of ... + "R_SPARC_PC_HH22": 37 , # Top 22 bits of pc rel 64 bit + "R_SPARC_PC_HM10": 38 , # High middle 10 bit of ... + "R_SPARC_PC_LM22": 39 , # Low miggle 22 bits of ... + "R_SPARC_WDISP16": 40 , # PC relative 16 bit shifted + "R_SPARC_WDISP19": 41 , # PC relative 19 bit shifted + "R_SPARC_GLOB_JMP": 42 , # was part of v9 ABI but was removed + "R_SPARC_7": 43 , # Direct 7 bit + "R_SPARC_5": 44 , # Direct 5 bit + "R_SPARC_6": 45 , # Direct 6 bit + "R_SPARC_DISP64": 46 , # PC relative 64 bit + "R_SPARC_PLT64": 47 , # Direct 64 bit ref to PLT entry + "R_SPARC_HIX22": 48 , # High 22 bit complemented + "R_SPARC_LOX10": 49 , # Truncated 11 bit complemented + "R_SPARC_H44": 50 , # Direct high 12 of 44 bit + "R_SPARC_M44": 51 , # Direct mid 22 of 44 bit + "R_SPARC_L44": 52 , # Direct low 10 of 44 bit + "R_SPARC_REGISTER": 53 , # Global register usage + "R_SPARC_UA64": 54 , # Direct 64 bit unaligned + "R_SPARC_UA16": 55 , # Direct 16 bit unaligned + "R_SPARC_TLS_GD_HI22": 56 , # + "R_SPARC_TLS_GD_LO10": 57 , # + "R_SPARC_TLS_GD_ADD": 58 , # + "R_SPARC_TLS_GD_CALL": 59 , # + "R_SPARC_TLS_LDM_HI22": 60 , # + "R_SPARC_TLS_LDM_LO10": 61 , # + "R_SPARC_TLS_LDM_ADD": 62 , # + "R_SPARC_TLS_LDM_CALL": 63 , # + "R_SPARC_TLS_LDO_HIX22": 64 , # + "R_SPARC_TLS_LDO_LOX10": 65 , # + "R_SPARC_TLS_LDO_ADD": 66 , # + "R_SPARC_TLS_IE_HI22": 67 , # + "R_SPARC_TLS_IE_LO10": 68 , # + "R_SPARC_TLS_IE_LD": 69 , # + "R_SPARC_TLS_IE_LDX": 70 , # + "R_SPARC_TLS_IE_ADD": 71 , # + "R_SPARC_TLS_LE_HIX22": 72 , # + "R_SPARC_TLS_LE_LOX10": 73 , # + "R_SPARC_TLS_DTPMOD32": 74 , # + "R_SPARC_TLS_DTPMOD64": 75 , # + "R_SPARC_TLS_DTPOFF32": 76 , # + "R_SPARC_TLS_DTPOFF64": 77 , # + "R_SPARC_TLS_TPOFF32": 78 , # + "R_SPARC_TLS_TPOFF64": 79 , # + "R_SPARC_GOTDATA_HIX22": 80 , # + "R_SPARC_GOTDATA_LOX10": 81 , # + "R_SPARC_GOTDATA_OP_HIX22": 82 , # + "R_SPARC_GOTDATA_OP_LOX10": 83 , # + "R_SPARC_GOTDATA_OP": 84 , # + "R_SPARC_H34": 85 , # + "R_SPARC_SIZE32": 86 , # + "R_SPARC_SIZE64": 87 , # + "R_SPARC_JMP_IREL": 248 , # + "R_SPARC_IRELATIVE": 249 , # + "R_SPARC_GNU_VTINHERIT": 250 , # + "R_SPARC_GNU_VTENTRY": 251 , # + "R_SPARC_REV32": 252 , # + "R_SPARC_NUM": 253 , # + "DT_SPARC_REGISTER": 0x70000001 , # + "DT_SPARC_NUM": 2 , # + "EF_MIPS_NOREORDER": 1 , # A .noreorder directive was used + "EF_MIPS_PIC": 2 , # Contains PIC code + "EF_MIPS_CPIC": 4 , # Uses PIC calling sequence + "EF_MIPS_XGOT": 8 , # + "EF_MIPS_64BIT_WHIRL": 16 , # + "EF_MIPS_ABI2": 32 , # + "EF_MIPS_ABI_ON32": 64 , # + "EF_MIPS_ARCH": 0xf0000000 , # MIPS architecture level + "EF_MIPS_ARCH_1": 0x00000000 , # -mips1 code. + "EF_MIPS_ARCH_2": 0x10000000 , # -mips2 code. + "EF_MIPS_ARCH_3": 0x20000000 , # -mips3 code. + "EF_MIPS_ARCH_4": 0x30000000 , # -mips4 code. + "EF_MIPS_ARCH_5": 0x40000000 , # -mips5 code. + "EF_MIPS_ARCH_32": 0x60000000 , # MIPS32 code. + "EF_MIPS_ARCH_64": 0x70000000 , # MIPS64 code. + "E_MIPS_ARCH_1": 0x00000000 , # -mips1 code. + "E_MIPS_ARCH_2": 0x10000000 , # -mips2 code. + "E_MIPS_ARCH_3": 0x20000000 , # -mips3 code. + "E_MIPS_ARCH_4": 0x30000000 , # -mips4 code. + "E_MIPS_ARCH_5": 0x40000000 , # -mips5 code. + "E_MIPS_ARCH_32": 0x60000000 , # MIPS32 code. + "E_MIPS_ARCH_64": 0x70000000 , # MIPS64 code. + "SHN_MIPS_ACOMMON": 0xff00 , # Allocated common symbols + "SHN_MIPS_TEXT": 0xff01 , # Allocated test symbols. + "SHN_MIPS_DATA": 0xff02 , # Allocated data symbols. + "SHN_MIPS_SCOMMON": 0xff03 , # Small common symbols + "SHN_MIPS_SUNDEFINED": 0xff04 , # Small undefined symbols + "SHT_MIPS_LIBLIST": 0x70000000 , # Shared objects used in link + "SHT_MIPS_MSYM": 0x70000001 , # + "SHT_MIPS_CONFLICT": 0x70000002 , # Conflicting symbols + "SHT_MIPS_GPTAB": 0x70000003 , # Global data area sizes + "SHT_MIPS_UCODE": 0x70000004 , # Reserved for SGI/MIPS compilers + "SHT_MIPS_DEBUG": 0x70000005 , # MIPS ECOFF debugging information + "SHT_MIPS_REGINFO": 0x70000006 , # Register usage information + "SHT_MIPS_PACKAGE": 0x70000007 , # + "SHT_MIPS_PACKSYM": 0x70000008 , # + "SHT_MIPS_RELD": 0x70000009 , # + "SHT_MIPS_IFACE": 0x7000000b , # + "SHT_MIPS_CONTENT": 0x7000000c , # + "SHT_MIPS_OPTIONS": 0x7000000d , # Miscellaneous options. + "SHT_MIPS_SHDR": 0x70000010 , # + "SHT_MIPS_FDESC": 0x70000011 , # + "SHT_MIPS_EXTSYM": 0x70000012 , # + "SHT_MIPS_DENSE": 0x70000013 , # + "SHT_MIPS_PDESC": 0x70000014 , # + "SHT_MIPS_LOCSYM": 0x70000015 , # + "SHT_MIPS_AUXSYM": 0x70000016 , # + "SHT_MIPS_OPTSYM": 0x70000017 , # + "SHT_MIPS_LOCSTR": 0x70000018 , # + "SHT_MIPS_LINE": 0x70000019 , # + "SHT_MIPS_RFDESC": 0x7000001a , # + "SHT_MIPS_DELTASYM": 0x7000001b , # + "SHT_MIPS_DELTAINST": 0x7000001c , # + "SHT_MIPS_DELTACLASS": 0x7000001d , # + "SHT_MIPS_DWARF": 0x7000001e , # DWARF debugging information. + "SHT_MIPS_DELTADECL": 0x7000001f , # + "SHT_MIPS_SYMBOL_LIB": 0x70000020 , # + "SHT_MIPS_EVENTS": 0x70000021 , # Event section. + "SHT_MIPS_TRANSLATE": 0x70000022 , # + "SHT_MIPS_PIXIE": 0x70000023 , # + "SHT_MIPS_XLATE": 0x70000024 , # + "SHT_MIPS_XLATE_DEBUG": 0x70000025 , # + "SHT_MIPS_WHIRL": 0x70000026 , # + "SHT_MIPS_EH_REGION": 0x70000027 , # + "SHT_MIPS_XLATE_OLD": 0x70000028 , # + "SHT_MIPS_PDR_EXCEPTION": 0x70000029 , # + "SHF_MIPS_GPREL": 0x10000000 , # Must be part of global data area + "SHF_MIPS_MERGE": 0x20000000 , # + "SHF_MIPS_ADDR": 0x40000000 , # + "SHF_MIPS_STRINGS": 0x80000000 , # + "SHF_MIPS_NOSTRIP": 0x08000000 , # + "SHF_MIPS_LOCAL": 0x04000000 , # + "SHF_MIPS_NAMES": 0x02000000 , # + "SHF_MIPS_NODUPE": 0x01000000 , # + "STO_MIPS_DEFAULT": 0x0 , # + "STO_MIPS_INTERNAL": 0x1 , # + "STO_MIPS_HIDDEN": 0x2 , # + "STO_MIPS_PROTECTED": 0x3 , # + "STO_MIPS_PLT": 0x8 , # + "STO_MIPS_SC_ALIGN_UNUSED": 0xff , # + "STB_MIPS_SPLIT_COMMON": 13 , # + "ODK_NULL": 0 , # Undefined. + "ODK_REGINFO": 1 , # Register usage information. + "ODK_EXCEPTIONS": 2 , # Exception processing options. + "ODK_PAD": 3 , # Section padding options. + "ODK_HWPATCH": 4 , # Hardware workarounds performed + "ODK_FILL": 5 , # record the fill value used by the linker. + "ODK_TAGS": 6 , # reserve space for desktop tools to write. + "ODK_HWAND": 7 , # HW workarounds. 'AND' bits when merging. + "ODK_HWOR": 8 , # HW workarounds. 'OR' bits when merging. + "OEX_FPU_MIN": 0x1f , # FPE's which MUST be enabled. + "OEX_FPU_MAX": 0x1f00 , # FPE's which MAY be enabled. + "OEX_PAGE0": 0x10000 , # page zero must be mapped. + "OEX_SMM": 0x20000 , # Force sequential memory mode? + "OEX_FPDBUG": 0x40000 , # Force floating point debug mode? + "OEX_PRECISEFP": MacroRef("OEX_FPDBUG") , # + "OEX_DISMISS": 0x80000 , # Dismiss invalid address faults? + "OEX_FPU_INVAL": 0x10 , # + "OEX_FPU_DIV0": 0x08 , # + "OEX_FPU_OFLO": 0x04 , # + "OEX_FPU_UFLO": 0x02 , # + "OEX_FPU_INEX": 0x01 , # + "OHW_R4KEOP": 0x1 , # R4000 end-of-page patch. + "OHW_R8KPFETCH": 0x2 , # may need R8000 prefetch patch. + "OHW_R5KEOP": 0x4 , # R5000 end-of-page patch. + "OHW_R5KCVTL": 0x8 , # R5000 cvt.[ds].l bug. clean=1. + "OPAD_PREFIX": 0x1 , # + "OPAD_POSTFIX": 0x2 , # + "OPAD_SYMBOL": 0x4 , # + "OHWA0_R4KEOP_CHECKED": 0x00000001 , # + "OHWA1_R4KEOP_CLEAN": 0x00000002 , # + "R_MIPS_NONE": 0 , # No reloc + "R_MIPS_16": 1 , # Direct 16 bit + "R_MIPS_32": 2 , # Direct 32 bit + "R_MIPS_REL32": 3 , # PC relative 32 bit + "R_MIPS_26": 4 , # Direct 26 bit shifted + "R_MIPS_HI16": 5 , # High 16 bit + "R_MIPS_LO16": 6 , # Low 16 bit + "R_MIPS_GPREL16": 7 , # GP relative 16 bit + "R_MIPS_LITERAL": 8 , # 16 bit literal entry + "R_MIPS_GOT16": 9 , # 16 bit GOT entry + "R_MIPS_PC16": 10 , # PC relative 16 bit + "R_MIPS_CALL16": 11 , # 16 bit GOT entry for function + "R_MIPS_GPREL32": 12 , # GP relative 32 bit + "R_MIPS_SHIFT5": 16 , # + "R_MIPS_SHIFT6": 17 , # + "R_MIPS_64": 18 , # + "R_MIPS_GOT_DISP": 19 , # + "R_MIPS_GOT_PAGE": 20 , # + "R_MIPS_GOT_OFST": 21 , # + "R_MIPS_GOT_HI16": 22 , # + "R_MIPS_GOT_LO16": 23 , # + "R_MIPS_SUB": 24 , # + "R_MIPS_INSERT_A": 25 , # + "R_MIPS_INSERT_B": 26 , # + "R_MIPS_DELETE": 27 , # + "R_MIPS_HIGHER": 28 , # + "R_MIPS_HIGHEST": 29 , # + "R_MIPS_CALL_HI16": 30 , # + "R_MIPS_CALL_LO16": 31 , # + "R_MIPS_SCN_DISP": 32 , # + "R_MIPS_REL16": 33 , # + "R_MIPS_ADD_IMMEDIATE": 34 , # + "R_MIPS_PJUMP": 35 , # + "R_MIPS_RELGOT": 36 , # + "R_MIPS_JALR": 37 , # + "R_MIPS_TLS_DTPMOD32": 38 , # Module number 32 bit + "R_MIPS_TLS_DTPREL32": 39 , # Module-relative offset 32 bit + "R_MIPS_TLS_DTPMOD64": 40 , # Module number 64 bit + "R_MIPS_TLS_DTPREL64": 41 , # Module-relative offset 64 bit + "R_MIPS_TLS_GD": 42 , # 16 bit GOT offset for GD + "R_MIPS_TLS_LDM": 43 , # 16 bit GOT offset for LDM + "R_MIPS_TLS_DTPREL_HI16": 44 , # Module-relative offset, high 16 bits + "R_MIPS_TLS_DTPREL_LO16": 45 , # Module-relative offset, low 16 bits + "R_MIPS_TLS_GOTTPREL": 46 , # 16 bit GOT offset for IE + "R_MIPS_TLS_TPREL32": 47 , # TP-relative offset, 32 bit + "R_MIPS_TLS_TPREL64": 48 , # TP-relative offset, 64 bit + "R_MIPS_TLS_TPREL_HI16": 49 , # TP-relative offset, high 16 bits + "R_MIPS_TLS_TPREL_LO16": 50 , # TP-relative offset, low 16 bits + "R_MIPS_GLOB_DAT": 51 , # + "R_MIPS_COPY": 126 , # + "R_MIPS_JUMP_SLOT": 127 , # + "R_MIPS_NUM": 128 , # + "PT_MIPS_REGINFO": 0x70000000 , # Register usage information + "PT_MIPS_RTPROC": 0x70000001 , # Runtime procedure table. + "PT_MIPS_OPTIONS": 0x70000002 , # + "PF_MIPS_LOCAL": 0x10000000 , # + "DT_MIPS_RLD_VERSION": 0x70000001 , # Runtime linker interface version + "DT_MIPS_TIME_STAMP": 0x70000002 , # Timestamp + "DT_MIPS_ICHECKSUM": 0x70000003 , # Checksum + "DT_MIPS_IVERSION": 0x70000004 , # Version string (string tbl index) + "DT_MIPS_FLAGS": 0x70000005 , # Flags + "DT_MIPS_BASE_ADDRESS": 0x70000006 , # Base address + "DT_MIPS_MSYM": 0x70000007 , # + "DT_MIPS_CONFLICT": 0x70000008 , # Address of CONFLICT section + "DT_MIPS_LIBLIST": 0x70000009 , # Address of LIBLIST section + "DT_MIPS_LOCAL_GOTNO": 0x7000000a , # Number of local GOT entries + "DT_MIPS_CONFLICTNO": 0x7000000b , # Number of CONFLICT entries + "DT_MIPS_LIBLISTNO": 0x70000010 , # Number of LIBLIST entries + "DT_MIPS_SYMTABNO": 0x70000011 , # Number of DYNSYM entries + "DT_MIPS_UNREFEXTNO": 0x70000012 , # First external DYNSYM + "DT_MIPS_GOTSYM": 0x70000013 , # First GOT entry in DYNSYM + "DT_MIPS_HIPAGENO": 0x70000014 , # Number of GOT page table entries + "DT_MIPS_RLD_MAP": 0x70000016 , # Address of run time loader map. + "DT_MIPS_DELTA_CLASS": 0x70000017 , # Delta C++ class definition. + "DT_MIPS_DELTA_CLASS_NO": 0x70000018 , # Number of entries in + "DT_MIPS_DELTA_INSTANCE": 0x70000019 , # Delta C++ class instances. + "DT_MIPS_DELTA_INSTANCE_NO": 0x7000001a , # Number of entries in + "DT_MIPS_DELTA_RELOC": 0x7000001b , # Delta relocations. + "DT_MIPS_DELTA_RELOC_NO": 0x7000001c , # Number of entries in + "DT_MIPS_DELTA_SYM": 0x7000001d , # Delta symbols that Delta + "DT_MIPS_DELTA_SYM_NO": 0x7000001e , # Number of entries in + "DT_MIPS_DELTA_CLASSSYM": 0x70000020 , # Delta symbols that hold the + "DT_MIPS_DELTA_CLASSSYM_NO": 0x70000021 , # Number of entries in + "DT_MIPS_CXX_FLAGS": 0x70000022 , # Flags indicating for C++ flavor. + "DT_MIPS_PIXIE_INIT": 0x70000023 , # + "DT_MIPS_SYMBOL_LIB": 0x70000024 , # + "DT_MIPS_LOCALPAGE_GOTIDX": 0x70000025 , # + "DT_MIPS_LOCAL_GOTIDX": 0x70000026 , # + "DT_MIPS_HIDDEN_GOTIDX": 0x70000027 , # + "DT_MIPS_PROTECTED_GOTIDX": 0x70000028 , # + "DT_MIPS_OPTIONS": 0x70000029 , # Address of .options. + "DT_MIPS_INTERFACE": 0x7000002a , # Address of .interface. + "DT_MIPS_DYNSTR_ALIGN": 0x7000002b , # + "DT_MIPS_INTERFACE_SIZE": 0x7000002c , # Size of the .interface section. + "DT_MIPS_RLD_TEXT_RESOLVE_ADDR": 0x7000002d , # Address of rld_text_rsolve + "DT_MIPS_PERF_SUFFIX": 0x7000002e , # Default suffix of dso to be added + "DT_MIPS_COMPACT_SIZE": 0x7000002f , # (O32)Size of compact rel section. + "DT_MIPS_GP_VALUE": 0x70000030 , # GP value for aux GOTs. + "DT_MIPS_AUX_DYNAMIC": 0x70000031 , # Address of aux .dynamic. + "DT_MIPS_PLTGOT": 0x70000032 , # + "DT_MIPS_RWPLT": 0x70000034 , # + "DT_MIPS_NUM": 0x35 , # + "RHF_NONE": 0 , # No flags + "RHF_QUICKSTART": (1 << 0) , # Use quickstart + "RHF_NOTPOT": (1 << 1) , # Hash size not power of 2 + "RHF_NO_LIBRARY_REPLACEMENT": (1 << 2) , # Ignore LD_LIBRARY_PATH + "RHF_NO_MOVE": (1 << 3) , # + "RHF_SGI_ONLY": (1 << 4) , # + "RHF_GUARANTEE_INIT": (1 << 5) , # + "RHF_DELTA_C_PLUS_PLUS": (1 << 6) , # + "RHF_GUARANTEE_START_INIT": (1 << 7) , # + "RHF_PIXIE": (1 << 8) , # + "RHF_DEFAULT_DELAY_LOAD": (1 << 9) , # + "RHF_REQUICKSTART": (1 << 10) , # + "RHF_REQUICKSTARTED": (1 << 11) , # + "RHF_CORD": (1 << 12) , # + "RHF_NO_UNRES_UNDEF": (1 << 13) , # + "RHF_RLD_ORDER_SAFE": (1 << 14) , # + "LL_NONE": 0 , # + "LL_EXACT_MATCH": (1 << 0) , # Require exact match + "LL_IGNORE_INT_VER": (1 << 1) , # Ignore interface version + "LL_REQUIRE_MINOR": (1 << 2) , # + "LL_EXPORTS": (1 << 3) , # + "LL_DELAY_LOAD": (1 << 4) , # + "LL_DELTA": (1 << 5) , # + "EF_PARISC_TRAPNIL": 0x00010000 , # Trap nil pointer dereference. + "EF_PARISC_EXT": 0x00020000 , # Program uses arch. extensions. + "EF_PARISC_LSB": 0x00040000 , # Program expects little endian. + "EF_PARISC_WIDE": 0x00080000 , # Program expects wide mode. + "EF_PARISC_NO_KABP": 0x00100000 , # No kernel assisted branch + "EF_PARISC_LAZYSWAP": 0x00400000 , # Allow lazy swapping. + "EF_PARISC_ARCH": 0x0000ffff , # Architecture version. + "EFA_PARISC_1_0": 0x020b , # PA-RISC 1.0 big-endian. + "EFA_PARISC_1_1": 0x0210 , # PA-RISC 1.1 big-endian. + "EFA_PARISC_2_0": 0x0214 , # PA-RISC 2.0 big-endian. + "SHN_PARISC_ANSI_COMMON": 0xff00 , # Section for tenatively declared + "SHN_PARISC_HUGE_COMMON": 0xff01 , # Common blocks in huge model. + "SHT_PARISC_EXT": 0x70000000 , # Contains product specific ext. + "SHT_PARISC_UNWIND": 0x70000001 , # Unwind information. + "SHT_PARISC_DOC": 0x70000002 , # Debug info for optimized code. + "SHF_PARISC_SHORT": 0x20000000 , # Section with short addressing. + "SHF_PARISC_HUGE": 0x40000000 , # Section far from gp. + "SHF_PARISC_SBP": 0x80000000 , # Static branch prediction code. + "STT_PARISC_MILLICODE": 13 , # Millicode function entry point. + "STT_HP_OPAQUE": (MacroRef("STT_LOOS") + 0x1) , # + "STT_HP_STUB": (MacroRef("STT_LOOS") + 0x2) , # + "R_PARISC_NONE": 0 , # No reloc. + "R_PARISC_DIR32": 1 , # Direct 32-bit reference. + "R_PARISC_DIR21L": 2 , # Left 21 bits of eff. address. + "R_PARISC_DIR17R": 3 , # Right 17 bits of eff. address. + "R_PARISC_DIR17F": 4 , # 17 bits of eff. address. + "R_PARISC_DIR14R": 6 , # Right 14 bits of eff. address. + "R_PARISC_PCREL32": 9 , # 32-bit rel. address. + "R_PARISC_PCREL21L": 10 , # Left 21 bits of rel. address. + "R_PARISC_PCREL17R": 11 , # Right 17 bits of rel. address. + "R_PARISC_PCREL17F": 12 , # 17 bits of rel. address. + "R_PARISC_PCREL14R": 14 , # Right 14 bits of rel. address. + "R_PARISC_DPREL21L": 18 , # Left 21 bits of rel. address. + "R_PARISC_DPREL14R": 22 , # Right 14 bits of rel. address. + "R_PARISC_GPREL21L": 26 , # GP-relative, left 21 bits. + "R_PARISC_GPREL14R": 30 , # GP-relative, right 14 bits. + "R_PARISC_LTOFF21L": 34 , # LT-relative, left 21 bits. + "R_PARISC_LTOFF14R": 38 , # LT-relative, right 14 bits. + "R_PARISC_SECREL32": 41 , # 32 bits section rel. address. + "R_PARISC_SEGBASE": 48 , # No relocation, set segment base. + "R_PARISC_SEGREL32": 49 , # 32 bits segment rel. address. + "R_PARISC_PLTOFF21L": 50 , # PLT rel. address, left 21 bits. + "R_PARISC_PLTOFF14R": 54 , # PLT rel. address, right 14 bits. + "R_PARISC_LTOFF_FPTR32": 57 , # 32 bits LT-rel. function pointer. + "R_PARISC_LTOFF_FPTR21L": 58 , # LT-rel. fct ptr, left 21 bits. + "R_PARISC_LTOFF_FPTR14R": 62 , # LT-rel. fct ptr, right 14 bits. + "R_PARISC_FPTR64": 64 , # 64 bits function address. + "R_PARISC_PLABEL32": 65 , # 32 bits function address. + "R_PARISC_PLABEL21L": 66 , # Left 21 bits of fdesc address. + "R_PARISC_PLABEL14R": 70 , # Right 14 bits of fdesc address. + "R_PARISC_PCREL64": 72 , # 64 bits PC-rel. address. + "R_PARISC_PCREL22F": 74 , # 22 bits PC-rel. address. + "R_PARISC_PCREL14WR": 75 , # PC-rel. address, right 14 bits. + "R_PARISC_PCREL14DR": 76 , # PC rel. address, right 14 bits. + "R_PARISC_PCREL16F": 77 , # 16 bits PC-rel. address. + "R_PARISC_PCREL16WF": 78 , # 16 bits PC-rel. address. + "R_PARISC_PCREL16DF": 79 , # 16 bits PC-rel. address. + "R_PARISC_DIR64": 80 , # 64 bits of eff. address. + "R_PARISC_DIR14WR": 83 , # 14 bits of eff. address. + "R_PARISC_DIR14DR": 84 , # 14 bits of eff. address. + "R_PARISC_DIR16F": 85 , # 16 bits of eff. address. + "R_PARISC_DIR16WF": 86 , # 16 bits of eff. address. + "R_PARISC_DIR16DF": 87 , # 16 bits of eff. address. + "R_PARISC_GPREL64": 88 , # 64 bits of GP-rel. address. + "R_PARISC_GPREL14WR": 91 , # GP-rel. address, right 14 bits. + "R_PARISC_GPREL14DR": 92 , # GP-rel. address, right 14 bits. + "R_PARISC_GPREL16F": 93 , # 16 bits GP-rel. address. + "R_PARISC_GPREL16WF": 94 , # 16 bits GP-rel. address. + "R_PARISC_GPREL16DF": 95 , # 16 bits GP-rel. address. + "R_PARISC_LTOFF64": 96 , # 64 bits LT-rel. address. + "R_PARISC_LTOFF14WR": 99 , # LT-rel. address, right 14 bits. + "R_PARISC_LTOFF14DR": 100 , # LT-rel. address, right 14 bits. + "R_PARISC_LTOFF16F": 101 , # 16 bits LT-rel. address. + "R_PARISC_LTOFF16WF": 102 , # 16 bits LT-rel. address. + "R_PARISC_LTOFF16DF": 103 , # 16 bits LT-rel. address. + "R_PARISC_SECREL64": 104 , # 64 bits section rel. address. + "R_PARISC_SEGREL64": 112 , # 64 bits segment rel. address. + "R_PARISC_PLTOFF14WR": 115 , # PLT-rel. address, right 14 bits. + "R_PARISC_PLTOFF14DR": 116 , # PLT-rel. address, right 14 bits. + "R_PARISC_PLTOFF16F": 117 , # 16 bits LT-rel. address. + "R_PARISC_PLTOFF16WF": 118 , # 16 bits PLT-rel. address. + "R_PARISC_PLTOFF16DF": 119 , # 16 bits PLT-rel. address. + "R_PARISC_LTOFF_FPTR64": 120 , # 64 bits LT-rel. function ptr. + "R_PARISC_LTOFF_FPTR14WR": 123 , # LT-rel. fct. ptr., right 14 bits. + "R_PARISC_LTOFF_FPTR14DR": 124 , # LT-rel. fct. ptr., right 14 bits. + "R_PARISC_LTOFF_FPTR16F": 125 , # 16 bits LT-rel. function ptr. + "R_PARISC_LTOFF_FPTR16WF": 126 , # 16 bits LT-rel. function ptr. + "R_PARISC_LTOFF_FPTR16DF": 127 , # 16 bits LT-rel. function ptr. + "R_PARISC_LORESERVE": 128 , # + "R_PARISC_COPY": 128 , # Copy relocation. + "R_PARISC_IPLT": 129 , # Dynamic reloc, imported PLT + "R_PARISC_EPLT": 130 , # Dynamic reloc, exported PLT + "R_PARISC_TPREL32": 153 , # 32 bits TP-rel. address. + "R_PARISC_TPREL21L": 154 , # TP-rel. address, left 21 bits. + "R_PARISC_TPREL14R": 158 , # TP-rel. address, right 14 bits. + "R_PARISC_LTOFF_TP21L": 162 , # LT-TP-rel. address, left 21 bits. + "R_PARISC_LTOFF_TP14R": 166 , # LT-TP-rel. address, right 14 bits. + "R_PARISC_LTOFF_TP14F": 167 , # 14 bits LT-TP-rel. address. + "R_PARISC_TPREL64": 216 , # 64 bits TP-rel. address. + "R_PARISC_TPREL14WR": 219 , # TP-rel. address, right 14 bits. + "R_PARISC_TPREL14DR": 220 , # TP-rel. address, right 14 bits. + "R_PARISC_TPREL16F": 221 , # 16 bits TP-rel. address. + "R_PARISC_TPREL16WF": 222 , # 16 bits TP-rel. address. + "R_PARISC_TPREL16DF": 223 , # 16 bits TP-rel. address. + "R_PARISC_LTOFF_TP64": 224 , # 64 bits LT-TP-rel. address. + "R_PARISC_LTOFF_TP14WR": 227 , # LT-TP-rel. address, right 14 bits. + "R_PARISC_LTOFF_TP14DR": 228 , # LT-TP-rel. address, right 14 bits. + "R_PARISC_LTOFF_TP16F": 229 , # 16 bits LT-TP-rel. address. + "R_PARISC_LTOFF_TP16WF": 230 , # 16 bits LT-TP-rel. address. + "R_PARISC_LTOFF_TP16DF": 231 , # 16 bits LT-TP-rel. address. + "R_PARISC_GNU_VTENTRY": 232 , # + "R_PARISC_GNU_VTINHERIT": 233 , # + "R_PARISC_TLS_GD21L": 234 , # GD 21-bit left. + "R_PARISC_TLS_GD14R": 235 , # GD 14-bit right. + "R_PARISC_TLS_GDCALL": 236 , # GD call to __t_g_a. + "R_PARISC_TLS_LDM21L": 237 , # LD module 21-bit left. + "R_PARISC_TLS_LDM14R": 238 , # LD module 14-bit right. + "R_PARISC_TLS_LDMCALL": 239 , # LD module call to __t_g_a. + "R_PARISC_TLS_LDO21L": 240 , # LD offset 21-bit left. + "R_PARISC_TLS_LDO14R": 241 , # LD offset 14-bit right. + "R_PARISC_TLS_DTPMOD32": 242 , # DTP module 32-bit. + "R_PARISC_TLS_DTPMOD64": 243 , # DTP module 64-bit. + "R_PARISC_TLS_DTPOFF32": 244 , # DTP offset 32-bit. + "R_PARISC_TLS_DTPOFF64": 245 , # DTP offset 32-bit. + "R_PARISC_TLS_LE21L": MacroRef("R_PARISC_TPREL21L"), # + "R_PARISC_TLS_LE14R": MacroRef("R_PARISC_TPREL14R"), # + "R_PARISC_TLS_IE21L": MacroRef("R_PARISC_LTOFF_TP21L") , # + "R_PARISC_TLS_IE14R": MacroRef("R_PARISC_LTOFF_TP14R") , # + "R_PARISC_TLS_TPREL32": MacroRef("R_PARISC_TPREL32") , # + "R_PARISC_TLS_TPREL64": MacroRef("R_PARISC_TPREL64") , # + "R_PARISC_HIRESERVE": 255 , # + "PT_HP_TLS": (MacroRef("PT_LOOS") + 0x0) , # + "PT_HP_CORE_NONE": (MacroRef("PT_LOOS") + 0x1) , # + "PT_HP_CORE_VERSION": (MacroRef("PT_LOOS") + 0x2) , # + "PT_HP_CORE_KERNEL": (MacroRef("PT_LOOS") + 0x3) , # + "PT_HP_CORE_COMM": (MacroRef("PT_LOOS") + 0x4) , # + "PT_HP_CORE_PROC": (MacroRef("PT_LOOS") + 0x5) , # + "PT_HP_CORE_LOADABLE": (MacroRef("PT_LOOS") + 0x6) , # + "PT_HP_CORE_STACK": (MacroRef("PT_LOOS") + 0x7) , # + "PT_HP_CORE_SHM": (MacroRef("PT_LOOS") + 0x8) , # + "PT_HP_CORE_MMF": (MacroRef("PT_LOOS") + 0x9) , # + "PT_HP_PARALLEL": (MacroRef("PT_LOOS") + 0x10) , # + "PT_HP_FASTBIND": (MacroRef("PT_LOOS") + 0x11) , # + "PT_HP_OPT_ANNOT": (MacroRef("PT_LOOS") + 0x12) , # + "PT_HP_HSL_ANNOT": (MacroRef("PT_LOOS") + 0x13) , # + "PT_HP_STACK": (MacroRef("PT_LOOS") + 0x14) , # + "PT_PARISC_ARCHEXT": 0x70000000 , # + "PT_PARISC_UNWIND": 0x70000001 , # + "PF_PARISC_SBP": 0x08000000 , # + "PF_HP_PAGE_SIZE": 0x00100000 , # + "PF_HP_FAR_SHARED": 0x00200000 , # + "PF_HP_NEAR_SHARED": 0x00400000 , # + "PF_HP_CODE": 0x01000000 , # + "PF_HP_MODIFY": 0x02000000 , # + "PF_HP_LAZYSWAP": 0x04000000 , # + "PF_HP_SBP": 0x08000000 , # + "EF_ALPHA_32BIT": 1 , # All addresses must be < 2GB. + "EF_ALPHA_CANRELAX": 2 , # Relocations for relaxing exist. + "SHT_ALPHA_DEBUG": 0x70000001 , # + "SHT_ALPHA_REGINFO": 0x70000002 , # + "SHF_ALPHA_GPREL": 0x10000000 , # + "STO_ALPHA_NOPV": 0x80 , # No PV required. + "STO_ALPHA_STD_GPLOAD": 0x88 , # PV only used for initial ldgp. + "R_ALPHA_NONE": 0 , # No reloc + "R_ALPHA_REFLONG": 1 , # Direct 32 bit + "R_ALPHA_REFQUAD": 2 , # Direct 64 bit + "R_ALPHA_GPREL32": 3 , # GP relative 32 bit + "R_ALPHA_LITERAL": 4 , # GP relative 16 bit w/optimization + "R_ALPHA_LITUSE": 5 , # Optimization hint for LITERAL + "R_ALPHA_GPDISP": 6 , # Add displacement to GP + "R_ALPHA_BRADDR": 7 , # PC+4 relative 23 bit shifted + "R_ALPHA_HINT": 8 , # PC+4 relative 16 bit shifted + "R_ALPHA_SREL16": 9 , # PC relative 16 bit + "R_ALPHA_SREL32": 10 , # PC relative 32 bit + "R_ALPHA_SREL64": 11 , # PC relative 64 bit + "R_ALPHA_GPRELHIGH": 17 , # GP relative 32 bit, high 16 bits + "R_ALPHA_GPRELLOW": 18 , # GP relative 32 bit, low 16 bits + "R_ALPHA_GPREL16": 19 , # GP relative 16 bit + "R_ALPHA_COPY": 24 , # Copy symbol at runtime + "R_ALPHA_GLOB_DAT": 25 , # Create GOT entry + "R_ALPHA_JMP_SLOT": 26 , # Create PLT entry + "R_ALPHA_RELATIVE": 27 , # Adjust by program base + "R_ALPHA_TLS_GD_HI": 28 , # + "R_ALPHA_TLSGD": 29 , # + "R_ALPHA_TLS_LDM": 30 , # + "R_ALPHA_DTPMOD64": 31 , # + "R_ALPHA_GOTDTPREL": 32 , # + "R_ALPHA_DTPREL64": 33 , # + "R_ALPHA_DTPRELHI": 34 , # + "R_ALPHA_DTPRELLO": 35 , # + "R_ALPHA_DTPREL16": 36 , # + "R_ALPHA_GOTTPREL": 37 , # + "R_ALPHA_TPREL64": 38 , # + "R_ALPHA_TPRELHI": 39 , # + "R_ALPHA_TPRELLO": 40 , # + "R_ALPHA_TPREL16": 41 , # + "R_ALPHA_NUM": 46 , # + "LITUSE_ALPHA_ADDR": 0 , # + "LITUSE_ALPHA_BASE": 1 , # + "LITUSE_ALPHA_BYTOFF": 2 , # + "LITUSE_ALPHA_JSR": 3 , # + "LITUSE_ALPHA_TLS_GD": 4 , # + "LITUSE_ALPHA_TLS_LDM": 5 , # + "DT_ALPHA_PLTRO": (MacroRef("DT_LOPROC") + 0) , # + "DT_ALPHA_NUM": 1 , # + "EF_PPC_EMB": 0x80000000 , # PowerPC embedded flag + "EF_PPC_RELOCATABLE": 0x00010000 , # PowerPC -mrelocatable flag + "EF_PPC_RELOCATABLE_LIB": 0x00008000 , # PowerPC -mrelocatable-lib + "R_PPC_NONE": 0 , # + "R_PPC_ADDR32": 1 , # 32bit absolute address + "R_PPC_ADDR24": 2 , # 26bit address, 2 bits ignored. + "R_PPC_ADDR16": 3 , # 16bit absolute address + "R_PPC_ADDR16_LO": 4 , # lower 16bit of absolute address + "R_PPC_ADDR16_HI": 5 , # high 16bit of absolute address + "R_PPC_ADDR16_HA": 6 , # adjusted high 16bit + "R_PPC_ADDR14": 7 , # 16bit address, 2 bits ignored + "R_PPC_ADDR14_BRTAKEN": 8 , # + "R_PPC_ADDR14_BRNTAKEN": 9 , # + "R_PPC_REL24": 10 , # PC relative 26 bit + "R_PPC_REL14": 11 , # PC relative 16 bit + "R_PPC_REL14_BRTAKEN": 12 , # + "R_PPC_REL14_BRNTAKEN": 13 , # + "R_PPC_GOT16": 14 , # + "R_PPC_GOT16_LO": 15 , # + "R_PPC_GOT16_HI": 16 , # + "R_PPC_GOT16_HA": 17 , # + "R_PPC_PLTREL24": 18 , # + "R_PPC_COPY": 19 , # + "R_PPC_GLOB_DAT": 20 , # + "R_PPC_JMP_SLOT": 21 , # + "R_PPC_RELATIVE": 22 , # + "R_PPC_LOCAL24PC": 23 , # + "R_PPC_UADDR32": 24 , # + "R_PPC_UADDR16": 25 , # + "R_PPC_REL32": 26 , # + "R_PPC_PLT32": 27 , # + "R_PPC_PLTREL32": 28 , # + "R_PPC_PLT16_LO": 29 , # + "R_PPC_PLT16_HI": 30 , # + "R_PPC_PLT16_HA": 31 , # + "R_PPC_SDAREL16": 32 , # + "R_PPC_SECTOFF": 33 , # + "R_PPC_SECTOFF_LO": 34 , # + "R_PPC_SECTOFF_HI": 35 , # + "R_PPC_SECTOFF_HA": 36 , # + "R_PPC_TLS": 67 , # none (sym+add)@tls + "R_PPC_DTPMOD32": 68 , # word32 (sym+add)@dtpmod + "R_PPC_TPREL16": 69 , # half16* (sym+add)@tprel + "R_PPC_TPREL16_LO": 70 , # half16 (sym+add)@tprel@l + "R_PPC_TPREL16_HI": 71 , # half16 (sym+add)@tprel@h + "R_PPC_TPREL16_HA": 72 , # half16 (sym+add)@tprel@ha + "R_PPC_TPREL32": 73 , # word32 (sym+add)@tprel + "R_PPC_DTPREL16": 74 , # half16* (sym+add)@dtprel + "R_PPC_DTPREL16_LO": 75 , # half16 (sym+add)@dtprel@l + "R_PPC_DTPREL16_HI": 76 , # half16 (sym+add)@dtprel@h + "R_PPC_DTPREL16_HA": 77 , # half16 (sym+add)@dtprel@ha + "R_PPC_DTPREL32": 78 , # word32 (sym+add)@dtprel + "R_PPC_GOT_TLSGD16": 79 , # half16* (sym+add)@got@tlsgd + "R_PPC_GOT_TLSGD16_LO": 80 , # half16 (sym+add)@got@tlsgd@l + "R_PPC_GOT_TLSGD16_HI": 81 , # half16 (sym+add)@got@tlsgd@h + "R_PPC_GOT_TLSGD16_HA": 82 , # half16 (sym+add)@got@tlsgd@ha + "R_PPC_GOT_TLSLD16": 83 , # half16* (sym+add)@got@tlsld + "R_PPC_GOT_TLSLD16_LO": 84 , # half16 (sym+add)@got@tlsld@l + "R_PPC_GOT_TLSLD16_HI": 85 , # half16 (sym+add)@got@tlsld@h + "R_PPC_GOT_TLSLD16_HA": 86 , # half16 (sym+add)@got@tlsld@ha + "R_PPC_GOT_TPREL16": 87 , # half16* (sym+add)@got@tprel + "R_PPC_GOT_TPREL16_LO": 88 , # half16 (sym+add)@got@tprel@l + "R_PPC_GOT_TPREL16_HI": 89 , # half16 (sym+add)@got@tprel@h + "R_PPC_GOT_TPREL16_HA": 90 , # half16 (sym+add)@got@tprel@ha + "R_PPC_GOT_DTPREL16": 91 , # half16* (sym+add)@got@dtprel + "R_PPC_GOT_DTPREL16_LO": 92 , # half16* (sym+add)@got@dtprel@l + "R_PPC_GOT_DTPREL16_HI": 93 , # half16* (sym+add)@got@dtprel@h + "R_PPC_GOT_DTPREL16_HA": 94 , # half16* (sym+add)@got@dtprel@ha + "R_PPC_EMB_NADDR32": 101 , # + "R_PPC_EMB_NADDR16": 102 , # + "R_PPC_EMB_NADDR16_LO": 103 , # + "R_PPC_EMB_NADDR16_HI": 104 , # + "R_PPC_EMB_NADDR16_HA": 105 , # + "R_PPC_EMB_SDAI16": 106 , # + "R_PPC_EMB_SDA2I16": 107 , # + "R_PPC_EMB_SDA2REL": 108 , # + "R_PPC_EMB_SDA21": 109 , # 16 bit offset in SDA + "R_PPC_EMB_MRKREF": 110 , # + "R_PPC_EMB_RELSEC16": 111 , # + "R_PPC_EMB_RELST_LO": 112 , # + "R_PPC_EMB_RELST_HI": 113 , # + "R_PPC_EMB_RELST_HA": 114 , # + "R_PPC_EMB_BIT_FLD": 115 , # + "R_PPC_EMB_RELSDA": 116 , # 16 bit relative offset in SDA + "R_PPC_DIAB_SDA21_LO": 180 , # like EMB_SDA21, but lower 16 bit + "R_PPC_DIAB_SDA21_HI": 181 , # like EMB_SDA21, but high 16 bit + "R_PPC_DIAB_SDA21_HA": 182 , # like EMB_SDA21, adjusted high 16 + "R_PPC_DIAB_RELSDA_LO": 183 , # like EMB_RELSDA, but lower 16 bit + "R_PPC_DIAB_RELSDA_HI": 184 , # like EMB_RELSDA, but high 16 bit + "R_PPC_DIAB_RELSDA_HA": 185 , # like EMB_RELSDA, adjusted high 16 + "R_PPC_IRELATIVE": 248 , # + "R_PPC_REL16": 249 , # half16 (sym+add-.) + "R_PPC_REL16_LO": 250 , # half16 (sym+add-.)@l + "R_PPC_REL16_HI": 251 , # half16 (sym+add-.)@h + "R_PPC_REL16_HA": 252 , # half16 (sym+add-.)@ha + "R_PPC_TOC16": 255 , # + "DT_PPC_GOT": (MacroRef("DT_LOPROC") + 0) , # + "DT_PPC_NUM": 1 , # + "R_PPC64_NONE": MacroRef("R_PPC_NONE") , # + "R_PPC64_ADDR32": MacroRef("R_PPC_ADDR32") , # 32bit absolute address + "R_PPC64_ADDR24": MacroRef("R_PPC_ADDR24") , # 26bit address, word aligned + "R_PPC64_ADDR16": MacroRef("R_PPC_ADDR16") , # 16bit absolute address + "R_PPC64_ADDR16_LO": MacroRef("R_PPC_ADDR16_LO") , # lower 16bits of address + "R_PPC64_ADDR16_HI": MacroRef("R_PPC_ADDR16_HI") , # high 16bits of address. + "R_PPC64_ADDR16_HA": MacroRef("R_PPC_ADDR16_HA") , # adjusted high 16bits. + "R_PPC64_ADDR14": MacroRef("R_PPC_ADDR14") , # 16bit address, word aligned + "R_PPC64_ADDR14_BRTAKEN": MacroRef("R_PPC_ADDR14_BRTAKEN") , # + "R_PPC64_ADDR14_BRNTAKEN": MacroRef("R_PPC_ADDR14_BRNTAKEN") , # + "R_PPC64_REL24": MacroRef("R_PPC_REL24") , # PC-rel. 26 bit, word aligned + "R_PPC64_REL14": MacroRef("R_PPC_REL14") , # PC relative 16 bit + "R_PPC64_REL14_BRTAKEN": MacroRef("R_PPC_REL14_BRTAKEN") , # + "R_PPC64_REL14_BRNTAKEN": MacroRef("R_PPC_REL14_BRNTAKEN") , # + "R_PPC64_GOT16": MacroRef("R_PPC_GOT16") , # + "R_PPC64_GOT16_LO": MacroRef("R_PPC_GOT16_LO") , # + "R_PPC64_GOT16_HI": MacroRef("R_PPC_GOT16_HI") , # + "R_PPC64_GOT16_HA": MacroRef("R_PPC_GOT16_HA") , # + "R_PPC64_COPY": MacroRef("R_PPC_COPY") , # + "R_PPC64_GLOB_DAT": MacroRef("R_PPC_GLOB_DAT") , # + "R_PPC64_JMP_SLOT": MacroRef("R_PPC_JMP_SLOT") , # + "R_PPC64_RELATIVE": MacroRef("R_PPC_RELATIVE") , # + "R_PPC64_UADDR32": MacroRef("R_PPC_UADDR32") , # + "R_PPC64_UADDR16": MacroRef("R_PPC_UADDR16") , # + "R_PPC64_REL32": MacroRef("R_PPC_REL32") , # + "R_PPC64_PLT32": MacroRef("R_PPC_PLT32") , # + "R_PPC64_PLTREL32": MacroRef("R_PPC_PLTREL32") , # + "R_PPC64_PLT16_LO": MacroRef("R_PPC_PLT16_LO") , # + "R_PPC64_PLT16_HI": MacroRef("R_PPC_PLT16_HI") , # + "R_PPC64_PLT16_HA": MacroRef("R_PPC_PLT16_HA") , # + "R_PPC64_SECTOFF": MacroRef("R_PPC_SECTOFF") , # + "R_PPC64_SECTOFF_LO": MacroRef("R_PPC_SECTOFF_LO") , # + "R_PPC64_SECTOFF_HI": MacroRef("R_PPC_SECTOFF_HI") , # + "R_PPC64_SECTOFF_HA": MacroRef("R_PPC_SECTOFF_HA") , # + "R_PPC64_ADDR30": 37 , # word30 (S + A - P) >> 2 + "R_PPC64_ADDR64": 38 , # doubleword64 S + A + "R_PPC64_ADDR16_HIGHER": 39 , # half16 #higher(S + A) + "R_PPC64_ADDR16_HIGHERA": 40 , # half16 #highera(S + A) + "R_PPC64_ADDR16_HIGHEST": 41 , # half16 #highest(S + A) + "R_PPC64_ADDR16_HIGHESTA": 42 , # half16 #highesta(S + A) + "R_PPC64_UADDR64": 43 , # doubleword64 S + A + "R_PPC64_REL64": 44 , # doubleword64 S + A - P + "R_PPC64_PLT64": 45 , # doubleword64 L + A + "R_PPC64_PLTREL64": 46 , # doubleword64 L + A - P + "R_PPC64_TOC16": 47 , # half16* S + A - .TOC + "R_PPC64_TOC16_LO": 48 , # half16 #lo(S + A - .TOC.) + "R_PPC64_TOC16_HI": 49 , # half16 #hi(S + A - .TOC.) + "R_PPC64_TOC16_HA": 50 , # half16 #ha(S + A - .TOC.) + "R_PPC64_TOC": 51 , # doubleword64 .TOC + "R_PPC64_PLTGOT16": 52 , # half16* M + A + "R_PPC64_PLTGOT16_LO": 53 , # half16 #lo(M + A) + "R_PPC64_PLTGOT16_HI": 54 , # half16 #hi(M + A) + "R_PPC64_PLTGOT16_HA": 55 , # half16 #ha(M + A) + "R_PPC64_ADDR16_DS": 56 , # half16ds* (S + A) >> 2 + "R_PPC64_ADDR16_LO_DS": 57 , # half16ds #lo(S + A) >> 2 + "R_PPC64_GOT16_DS": 58 , # half16ds* (G + A) >> 2 + "R_PPC64_GOT16_LO_DS": 59 , # half16ds #lo(G + A) >> 2 + "R_PPC64_PLT16_LO_DS": 60 , # half16ds #lo(L + A) >> 2 + "R_PPC64_SECTOFF_DS": 61 , # half16ds* (R + A) >> 2 + "R_PPC64_SECTOFF_LO_DS": 62 , # half16ds #lo(R + A) >> 2 + "R_PPC64_TOC16_DS": 63 , # half16ds* (S + A - .TOC.) >> 2 + "R_PPC64_TOC16_LO_DS": 64 , # half16ds #lo(S + A - .TOC.) >> 2 + "R_PPC64_PLTGOT16_DS": 65 , # half16ds* (M + A) >> 2 + "R_PPC64_PLTGOT16_LO_DS": 66 , # half16ds #lo(M + A) >> 2 + "R_PPC64_TLS": 67 , # none (sym+add)@tls + "R_PPC64_DTPMOD64": 68 , # doubleword64 (sym+add)@dtpmod + "R_PPC64_TPREL16": 69 , # half16* (sym+add)@tprel + "R_PPC64_TPREL16_LO": 70 , # half16 (sym+add)@tprel@l + "R_PPC64_TPREL16_HI": 71 , # half16 (sym+add)@tprel@h + "R_PPC64_TPREL16_HA": 72 , # half16 (sym+add)@tprel@ha + "R_PPC64_TPREL64": 73 , # doubleword64 (sym+add)@tprel + "R_PPC64_DTPREL16": 74 , # half16* (sym+add)@dtprel + "R_PPC64_DTPREL16_LO": 75 , # half16 (sym+add)@dtprel@l + "R_PPC64_DTPREL16_HI": 76 , # half16 (sym+add)@dtprel@h + "R_PPC64_DTPREL16_HA": 77 , # half16 (sym+add)@dtprel@ha + "R_PPC64_DTPREL64": 78 , # doubleword64 (sym+add)@dtprel + "R_PPC64_GOT_TLSGD16": 79 , # half16* (sym+add)@got@tlsgd + "R_PPC64_GOT_TLSGD16_LO": 80 , # half16 (sym+add)@got@tlsgd@l + "R_PPC64_GOT_TLSGD16_HI": 81 , # half16 (sym+add)@got@tlsgd@h + "R_PPC64_GOT_TLSGD16_HA": 82 , # half16 (sym+add)@got@tlsgd@ha + "R_PPC64_GOT_TLSLD16": 83 , # half16* (sym+add)@got@tlsld + "R_PPC64_GOT_TLSLD16_LO": 84 , # half16 (sym+add)@got@tlsld@l + "R_PPC64_GOT_TLSLD16_HI": 85 , # half16 (sym+add)@got@tlsld@h + "R_PPC64_GOT_TLSLD16_HA": 86 , # half16 (sym+add)@got@tlsld@ha + "R_PPC64_GOT_TPREL16_DS": 87 , # half16ds* (sym+add)@got@tprel + "R_PPC64_GOT_TPREL16_LO_DS": 88 , # half16ds (sym+add)@got@tprel@l + "R_PPC64_GOT_TPREL16_HI": 89 , # half16 (sym+add)@got@tprel@h + "R_PPC64_GOT_TPREL16_HA": 90 , # half16 (sym+add)@got@tprel@ha + "R_PPC64_GOT_DTPREL16_DS": 91 , # half16ds* (sym+add)@got@dtprel + "R_PPC64_GOT_DTPREL16_LO_DS": 92 , # half16ds (sym+add)@got@dtprel@l + "R_PPC64_GOT_DTPREL16_HI": 93 , # half16 (sym+add)@got@dtprel@h + "R_PPC64_GOT_DTPREL16_HA": 94 , # half16 (sym+add)@got@dtprel@ha + "R_PPC64_TPREL16_DS": 95 , # half16ds* (sym+add)@tprel + "R_PPC64_TPREL16_LO_DS": 96 , # half16ds (sym+add)@tprel@l + "R_PPC64_TPREL16_HIGHER": 97 , # half16 (sym+add)@tprel@higher + "R_PPC64_TPREL16_HIGHERA": 98 , # half16 (sym+add)@tprel@highera + "R_PPC64_TPREL16_HIGHEST": 99 , # half16 (sym+add)@tprel@highest + "R_PPC64_TPREL16_HIGHESTA": 100 , # half16 (sym+add)@tprel@highesta + "R_PPC64_DTPREL16_DS": 101 , # half16ds* (sym+add)@dtprel + "R_PPC64_DTPREL16_LO_DS": 102 , # half16ds (sym+add)@dtprel@l + "R_PPC64_DTPREL16_HIGHER": 103 , # half16 (sym+add)@dtprel@higher + "R_PPC64_DTPREL16_HIGHERA": 104 , # half16 (sym+add)@dtprel@highera + "R_PPC64_DTPREL16_HIGHEST": 105 , # half16 (sym+add)@dtprel@highest + "R_PPC64_DTPREL16_HIGHESTA": 106 , # half16 (sym+add)@dtprel@highesta + "R_PPC64_JMP_IREL": 247 , # + "R_PPC64_IRELATIVE": 248 , # + "R_PPC64_REL16": 249 , # half16 (sym+add-.) + "R_PPC64_REL16_LO": 250 , # half16 (sym+add-.)@l + "R_PPC64_REL16_HI": 251 , # half16 (sym+add-.)@h + "R_PPC64_REL16_HA": 252 , # half16 (sym+add-.)@ha + "DT_PPC64_GLINK": (MacroRef("DT_LOPROC") + 0) , # + "DT_PPC64_OPD": (MacroRef("DT_LOPROC") + 1) , # + "DT_PPC64_OPDSZ": (MacroRef("DT_LOPROC") + 2) , # + "DT_PPC64_NUM": 3 , # + "EF_ARM_RELEXEC": 0x01 , # + "EF_ARM_HASENTRY": 0x02 , # + "EF_ARM_INTERWORK": 0x04 , # + "EF_ARM_APCS_26": 0x08 , # + "EF_ARM_APCS_FLOAT": 0x10 , # + "EF_ARM_PIC": 0x20 , # + "EF_ARM_ALIGN8": 0x40 , # 8-bit structure alignment is in use + "EF_ARM_NEW_ABI": 0x80 , # + "EF_ARM_OLD_ABI": 0x100 , # + "EF_ARM_SOFT_FLOAT": 0x200 , # + "EF_ARM_VFP_FLOAT": 0x400 , # + "EF_ARM_MAVERICK_FLOAT": 0x800 , # + "EF_ARM_SYMSARESORTED": 0x04 , # + "EF_ARM_DYNSYMSUSESEGIDX": 0x08 , # + "EF_ARM_MAPSYMSFIRST": 0x10 , # + "EF_ARM_EABIMASK": 0XFF000000 , # + "EF_ARM_BE8": 0x00800000 , # + "EF_ARM_LE8": 0x00400000 , # + "EF_ARM_EABI_UNKNOWN": 0x00000000 , # + "EF_ARM_EABI_VER1": 0x01000000 , # + "EF_ARM_EABI_VER2": 0x02000000 , # + "EF_ARM_EABI_VER3": 0x03000000 , # + "EF_ARM_EABI_VER4": 0x04000000 , # + "EF_ARM_EABI_VER5": 0x05000000 , # + "STT_ARM_TFUNC": MacroRef("STT_LOPROC") , # A Thumb function. + "STT_ARM_16BIT": MacroRef("STT_HIPROC") , # A Thumb label. + "SHF_ARM_ENTRYSECT": 0x10000000 , # Section contains an entry point + "SHF_ARM_COMDEF": 0x80000000 , # Section may be multiply defined + "PF_ARM_SB": 0x10000000 , # Segment contains the location + "PF_ARM_PI": 0x20000000 , # Position-independent segment. + "PF_ARM_ABS": 0x40000000 , # Absolute segment. + "PT_ARM_EXIDX": (MacroRef("PT_LOPROC") + 1) , # ARM unwind segment. + "SHT_ARM_EXIDX": (MacroRef("SHT_LOPROC") + 1) , # ARM unwind section. + "SHT_ARM_PREEMPTMAP": (MacroRef("SHT_LOPROC") + 2) , # Preemption details. + "SHT_ARM_ATTRIBUTES": (MacroRef("SHT_LOPROC") + 3) , # ARM attributes section. + "R_ARM_NONE": 0 , # No reloc + "R_ARM_PC24": 1 , # PC relative 26 bit branch + "R_ARM_ABS32": 2 , # Direct 32 bit + "R_ARM_REL32": 3 , # PC relative 32 bit + "R_ARM_PC13": 4 , # + "R_ARM_ABS16": 5 , # Direct 16 bit + "R_ARM_ABS12": 6 , # Direct 12 bit + "R_ARM_THM_ABS5": 7 , # + "R_ARM_ABS8": 8 , # Direct 8 bit + "R_ARM_SBREL32": 9 , # + "R_ARM_THM_PC22": 10 , # + "R_ARM_THM_PC8": 11 , # + "R_ARM_AMP_VCALL9": 12 , # + "R_ARM_SWI24": 13 , # Obsolete static relocation. + "R_ARM_TLS_DESC": 13 , # Dynamic relocation. + "R_ARM_THM_SWI8": 14 , # + "R_ARM_XPC25": 15 , # + "R_ARM_THM_XPC22": 16 , # + "R_ARM_TLS_DTPMOD32": 17 , # ID of module containing symbol + "R_ARM_TLS_DTPOFF32": 18 , # Offset in TLS block + "R_ARM_TLS_TPOFF32": 19 , # Offset in static TLS block + "R_ARM_COPY": 20 , # Copy symbol at runtime + "R_ARM_GLOB_DAT": 21 , # Create GOT entry + "R_ARM_JUMP_SLOT": 22 , # Create PLT entry + "R_ARM_RELATIVE": 23 , # Adjust by program base + "R_ARM_GOTOFF": 24 , # 32 bit offset to GOT + "R_ARM_GOTPC": 25 , # 32 bit PC relative offset to GOT + "R_ARM_GOT32": 26 , # 32 bit GOT entry + "R_ARM_PLT32": 27 , # 32 bit PLT address + "R_ARM_ALU_PCREL_7_0": 32 , # + "R_ARM_ALU_PCREL_15_8": 33 , # + "R_ARM_ALU_PCREL_23_15": 34 , # + "R_ARM_LDR_SBREL_11_0": 35 , # + "R_ARM_ALU_SBREL_19_12": 36 , # + "R_ARM_ALU_SBREL_27_20": 37 , # + "R_ARM_TLS_GOTDESC": 90 , # + "R_ARM_TLS_CALL": 91 , # + "R_ARM_TLS_DESCSEQ": 92 , # + "R_ARM_THM_TLS_CALL": 93 , # + "R_ARM_GNU_VTENTRY": 100 , # + "R_ARM_GNU_VTINHERIT": 101 , # + "R_ARM_THM_PC11": 102 , # thumb unconditional branch + "R_ARM_THM_PC9": 103 , # thumb conditional branch + "R_ARM_TLS_GD32": 104 , # PC-rel 32 bit for global dynamic + "R_ARM_TLS_LDM32": 105 , # PC-rel 32 bit for local dynamic + "R_ARM_TLS_LDO32": 106 , # 32 bit offset relative to TLS + "R_ARM_TLS_IE32": 107 , # PC-rel 32 bit for GOT entry of + "R_ARM_TLS_LE32": 108 , # 32 bit offset relative to static + "R_ARM_THM_TLS_DESCSEQ": 129 , # + "R_ARM_IRELATIVE": 160 , # + "R_ARM_RXPC25": 249 , # + "R_ARM_RSBREL32": 250 , # + "R_ARM_THM_RPC22": 251 , # + "R_ARM_RREL32": 252 , # + "R_ARM_RABS22": 253 , # + "R_ARM_RPC24": 254 , # + "R_ARM_RBASE": 255 , # + "R_ARM_NUM": 256 , # + "EF_IA_64_MASKOS": 0x0000000f , # os-specific flags + "EF_IA_64_ABI64": 0x00000010 , # 64-bit ABI + "EF_IA_64_ARCH": 0xff000000 , # arch. version mask + "PT_IA_64_ARCHEXT": (MacroRef("PT_LOPROC") + 0) , # arch extension bits + "PT_IA_64_UNWIND": (MacroRef("PT_LOPROC") + 1) , # ia64 unwind bits + "PT_IA_64_HP_OPT_ANOT": (MacroRef("PT_LOOS") + 0x12) , # + "PT_IA_64_HP_HSL_ANOT": (MacroRef("PT_LOOS") + 0x13) , # + "PT_IA_64_HP_STACK": (MacroRef("PT_LOOS") + 0x14) , # + "PF_IA_64_NORECOV": 0x80000000 , # spec insns w/o recovery + "SHT_IA_64_EXT": (MacroRef("SHT_LOPROC") + 0) , # extension bits + "SHT_IA_64_UNWIND": (MacroRef("SHT_LOPROC") + 1) , # unwind bits + "SHF_IA_64_SHORT": 0x10000000 , # section near gp + "SHF_IA_64_NORECOV": 0x20000000 , # spec insns w/o recovery + "DT_IA_64_PLT_RESERVE": (MacroRef("DT_LOPROC") + 0) , # + "DT_IA_64_NUM": 1 , # + "R_IA64_NONE": 0x00 , # none + "R_IA64_IMM14": 0x21 , # symbol + addend, add imm14 + "R_IA64_IMM22": 0x22 , # symbol + addend, add imm22 + "R_IA64_IMM64": 0x23 , # symbol + addend, mov imm64 + "R_IA64_DIR32MSB": 0x24 , # symbol + addend, data4 MSB + "R_IA64_DIR32LSB": 0x25 , # symbol + addend, data4 LSB + "R_IA64_DIR64MSB": 0x26 , # symbol + addend, data8 MSB + "R_IA64_DIR64LSB": 0x27 , # symbol + addend, data8 LSB + "R_IA64_GPREL22": 0x2a , # @gprel(sym + add), add imm22 + "R_IA64_GPREL64I": 0x2b , # @gprel(sym + add), mov imm64 + "R_IA64_GPREL32MSB": 0x2c , # @gprel(sym + add), data4 MSB + "R_IA64_GPREL32LSB": 0x2d , # @gprel(sym + add), data4 LSB + "R_IA64_GPREL64MSB": 0x2e , # @gprel(sym + add), data8 MSB + "R_IA64_GPREL64LSB": 0x2f , # @gprel(sym + add), data8 LSB + "R_IA64_LTOFF22": 0x32 , # @ltoff(sym + add), add imm22 + "R_IA64_LTOFF64I": 0x33 , # @ltoff(sym + add), mov imm64 + "R_IA64_PLTOFF22": 0x3a , # @pltoff(sym + add), add imm22 + "R_IA64_PLTOFF64I": 0x3b , # @pltoff(sym + add), mov imm64 + "R_IA64_PLTOFF64MSB": 0x3e , # @pltoff(sym + add), data8 MSB + "R_IA64_PLTOFF64LSB": 0x3f , # @pltoff(sym + add), data8 LSB + "R_IA64_FPTR64I": 0x43 , # @fptr(sym + add), mov imm64 + "R_IA64_FPTR32MSB": 0x44 , # @fptr(sym + add), data4 MSB + "R_IA64_FPTR32LSB": 0x45 , # @fptr(sym + add), data4 LSB + "R_IA64_FPTR64MSB": 0x46 , # @fptr(sym + add), data8 MSB + "R_IA64_FPTR64LSB": 0x47 , # @fptr(sym + add), data8 LSB + "R_IA64_PCREL60B": 0x48 , # @pcrel(sym + add), brl + "R_IA64_PCREL21B": 0x49 , # @pcrel(sym + add), ptb, call + "R_IA64_PCREL21M": 0x4a , # @pcrel(sym + add), chk.s + "R_IA64_PCREL21F": 0x4b , # @pcrel(sym + add), fchkf + "R_IA64_PCREL32MSB": 0x4c , # @pcrel(sym + add), data4 MSB + "R_IA64_PCREL32LSB": 0x4d , # @pcrel(sym + add), data4 LSB + "R_IA64_PCREL64MSB": 0x4e , # @pcrel(sym + add), data8 MSB + "R_IA64_PCREL64LSB": 0x4f , # @pcrel(sym + add), data8 LSB + "R_IA64_LTOFF_FPTR22": 0x52 , # @ltoff(@fptr(s+a)), imm22 + "R_IA64_LTOFF_FPTR64I": 0x53 , # @ltoff(@fptr(s+a)), imm64 + "R_IA64_LTOFF_FPTR32MSB": 0x54 , # @ltoff(@fptr(s+a)), data4 MSB + "R_IA64_LTOFF_FPTR32LSB": 0x55 , # @ltoff(@fptr(s+a)), data4 LSB + "R_IA64_LTOFF_FPTR64MSB": 0x56 , # @ltoff(@fptr(s+a)), data8 MSB + "R_IA64_LTOFF_FPTR64LSB": 0x57 , # @ltoff(@fptr(s+a)), data8 LSB + "R_IA64_SEGREL32MSB": 0x5c , # @segrel(sym + add), data4 MSB + "R_IA64_SEGREL32LSB": 0x5d , # @segrel(sym + add), data4 LSB + "R_IA64_SEGREL64MSB": 0x5e , # @segrel(sym + add), data8 MSB + "R_IA64_SEGREL64LSB": 0x5f , # @segrel(sym + add), data8 LSB + "R_IA64_SECREL32MSB": 0x64 , # @secrel(sym + add), data4 MSB + "R_IA64_SECREL32LSB": 0x65 , # @secrel(sym + add), data4 LSB + "R_IA64_SECREL64MSB": 0x66 , # @secrel(sym + add), data8 MSB + "R_IA64_SECREL64LSB": 0x67 , # @secrel(sym + add), data8 LSB + "R_IA64_REL32MSB": 0x6c , # data 4 + REL + "R_IA64_REL32LSB": 0x6d , # data 4 + REL + "R_IA64_REL64MSB": 0x6e , # data 8 + REL + "R_IA64_REL64LSB": 0x6f , # data 8 + REL + "R_IA64_LTV32MSB": 0x74 , # symbol + addend, data4 MSB + "R_IA64_LTV32LSB": 0x75 , # symbol + addend, data4 LSB + "R_IA64_LTV64MSB": 0x76 , # symbol + addend, data8 MSB + "R_IA64_LTV64LSB": 0x77 , # symbol + addend, data8 LSB + "R_IA64_PCREL21BI": 0x79 , # @pcrel(sym + add), 21bit inst + "R_IA64_PCREL22": 0x7a , # @pcrel(sym + add), 22bit inst + "R_IA64_PCREL64I": 0x7b , # @pcrel(sym + add), 64bit inst + "R_IA64_IPLTMSB": 0x80 , # dynamic reloc, imported PLT, MSB + "R_IA64_IPLTLSB": 0x81 , # dynamic reloc, imported PLT, LSB + "R_IA64_COPY": 0x84 , # copy relocation + "R_IA64_SUB": 0x85 , # Addend and symbol difference + "R_IA64_LTOFF22X": 0x86 , # LTOFF22, relaxable. + "R_IA64_LDXMOV": 0x87 , # Use of LTOFF22X. + "R_IA64_TPREL14": 0x91 , # @tprel(sym + add), imm14 + "R_IA64_TPREL22": 0x92 , # @tprel(sym + add), imm22 + "R_IA64_TPREL64I": 0x93 , # @tprel(sym + add), imm64 + "R_IA64_TPREL64MSB": 0x96 , # @tprel(sym + add), data8 MSB + "R_IA64_TPREL64LSB": 0x97 , # @tprel(sym + add), data8 LSB + "R_IA64_LTOFF_TPREL22": 0x9a , # @ltoff(@tprel(s+a)), imm2 + "R_IA64_DTPMOD64MSB": 0xa6 , # @dtpmod(sym + add), data8 MSB + "R_IA64_DTPMOD64LSB": 0xa7 , # @dtpmod(sym + add), data8 LSB + "R_IA64_LTOFF_DTPMOD22": 0xaa , # @ltoff(@dtpmod(sym + add)), imm22 + "R_IA64_DTPREL14": 0xb1 , # @dtprel(sym + add), imm14 + "R_IA64_DTPREL22": 0xb2 , # @dtprel(sym + add), imm22 + "R_IA64_DTPREL64I": 0xb3 , # @dtprel(sym + add), imm64 + "R_IA64_DTPREL32MSB": 0xb4 , # @dtprel(sym + add), data4 MSB + "R_IA64_DTPREL32LSB": 0xb5 , # @dtprel(sym + add), data4 LSB + "R_IA64_DTPREL64MSB": 0xb6 , # @dtprel(sym + add), data8 MSB + "R_IA64_DTPREL64LSB": 0xb7 , # @dtprel(sym + add), data8 LSB + "R_IA64_LTOFF_DTPREL22": 0xba , # @ltoff(@dtprel(s+a)), imm22 + "EF_SH_MACH_MASK": 0x1f , # + "EF_SH_UNKNOWN": 0x0 , # + "EF_SH1": 0x1 , # + "EF_SH2": 0x2 , # + "EF_SH3": 0x3 , # + "EF_SH_DSP": 0x4 , # + "EF_SH3_DSP": 0x5 , # + "EF_SH4AL_DSP": 0x6 , # + "EF_SH3E": 0x8 , # + "EF_SH4": 0x9 , # + "EF_SH2E": 0xb , # + "EF_SH4A": 0xc , # + "EF_SH2A": 0xd , # + "EF_SH4_NOFPU": 0x10 , # + "EF_SH4A_NOFPU": 0x11 , # + "EF_SH4_NOMMU_NOFPU": 0x12 , # + "EF_SH2A_NOFPU": 0x13 , # + "EF_SH3_NOMMU": 0x14 , # + "EF_SH2A_SH4_NOFPU": 0x15 , # + "EF_SH2A_SH3_NOFPU": 0x16 , # + "EF_SH2A_SH4": 0x17 , # + "EF_SH2A_SH3E": 0x18 , # + "R_SH_NONE": 0 , # + "R_SH_DIR32": 1 , # + "R_SH_REL32": 2 , # + "R_SH_DIR8WPN": 3 , # + "R_SH_IND12W": 4 , # + "R_SH_DIR8WPL": 5 , # + "R_SH_DIR8WPZ": 6 , # + "R_SH_DIR8BP": 7 , # + "R_SH_DIR8W": 8 , # + "R_SH_DIR8L": 9 , # + "R_SH_SWITCH16": 25 , # + "R_SH_SWITCH32": 26 , # + "R_SH_USES": 27 , # + "R_SH_COUNT": 28 , # + "R_SH_ALIGN": 29 , # + "R_SH_CODE": 30 , # + "R_SH_DATA": 31 , # + "R_SH_LABEL": 32 , # + "R_SH_SWITCH8": 33 , # + "R_SH_GNU_VTINHERIT": 34 , # + "R_SH_GNU_VTENTRY": 35 , # + "R_SH_TLS_GD_32": 144 , # + "R_SH_TLS_LD_32": 145 , # + "R_SH_TLS_LDO_32": 146 , # + "R_SH_TLS_IE_32": 147 , # + "R_SH_TLS_LE_32": 148 , # + "R_SH_TLS_DTPMOD32": 149 , # + "R_SH_TLS_DTPOFF32": 150 , # + "R_SH_TLS_TPOFF32": 151 , # + "R_SH_GOT32": 160 , # + "R_SH_PLT32": 161 , # + "R_SH_COPY": 162 , # + "R_SH_GLOB_DAT": 163 , # + "R_SH_JMP_SLOT": 164 , # + "R_SH_RELATIVE": 165 , # + "R_SH_GOTOFF": 166 , # + "R_SH_GOTPC": 167 , # + "R_SH_NUM": 256 , # + "EF_S390_HIGH_GPRS": 0x00000001 , # High GPRs kernel facility needed. + "R_390_NONE": 0 , # No reloc. + "R_390_8": 1 , # Direct 8 bit. + "R_390_12": 2 , # Direct 12 bit. + "R_390_16": 3 , # Direct 16 bit. + "R_390_32": 4 , # Direct 32 bit. + "R_390_PC32": 5 , # PC relative 32 bit. + "R_390_GOT12": 6 , # 12 bit GOT offset. + "R_390_GOT32": 7 , # 32 bit GOT offset. + "R_390_PLT32": 8 , # 32 bit PC relative PLT address. + "R_390_COPY": 9 , # Copy symbol at runtime. + "R_390_GLOB_DAT": 10 , # Create GOT entry. + "R_390_JMP_SLOT": 11 , # Create PLT entry. + "R_390_RELATIVE": 12 , # Adjust by program base. + "R_390_GOTOFF32": 13 , # 32 bit offset to GOT. + "R_390_GOTPC": 14 , # 32 bit PC relative offset to GOT. + "R_390_GOT16": 15 , # 16 bit GOT offset. + "R_390_PC16": 16 , # PC relative 16 bit. + "R_390_PC16DBL": 17 , # PC relative 16 bit shifted by 1. + "R_390_PLT16DBL": 18 , # 16 bit PC rel. PLT shifted by 1. + "R_390_PC32DBL": 19 , # PC relative 32 bit shifted by 1. + "R_390_PLT32DBL": 20 , # 32 bit PC rel. PLT shifted by 1. + "R_390_GOTPCDBL": 21 , # 32 bit PC rel. GOT shifted by 1. + "R_390_64": 22 , # Direct 64 bit. + "R_390_PC64": 23 , # PC relative 64 bit. + "R_390_GOT64": 24 , # 64 bit GOT offset. + "R_390_PLT64": 25 , # 64 bit PC relative PLT address. + "R_390_GOTENT": 26 , # 32 bit PC rel. to GOT entry >> 1. + "R_390_GOTOFF16": 27 , # 16 bit offset to GOT. + "R_390_GOTOFF64": 28 , # 64 bit offset to GOT. + "R_390_GOTPLT12": 29 , # 12 bit offset to jump slot. + "R_390_GOTPLT16": 30 , # 16 bit offset to jump slot. + "R_390_GOTPLT32": 31 , # 32 bit offset to jump slot. + "R_390_GOTPLT64": 32 , # 64 bit offset to jump slot. + "R_390_GOTPLTENT": 33 , # 32 bit rel. offset to jump slot. + "R_390_PLTOFF16": 34 , # 16 bit offset from GOT to PLT. + "R_390_PLTOFF32": 35 , # 32 bit offset from GOT to PLT. + "R_390_PLTOFF64": 36 , # 16 bit offset from GOT to PLT. + "R_390_TLS_LOAD": 37 , # Tag for load insn in TLS code. + "R_390_TLS_GDCALL": 38 , # Tag for function call in general + "R_390_TLS_LDCALL": 39 , # Tag for function call in local + "R_390_TLS_GD32": 40 , # Direct 32 bit for general dynamic + "R_390_TLS_GD64": 41 , # Direct 64 bit for general dynamic + "R_390_TLS_GOTIE12": 42 , # 12 bit GOT offset for static TLS + "R_390_TLS_GOTIE32": 43 , # 32 bit GOT offset for static TLS + "R_390_TLS_GOTIE64": 44 , # 64 bit GOT offset for static TLS + "R_390_TLS_LDM32": 45 , # Direct 32 bit for local dynamic + "R_390_TLS_LDM64": 46 , # Direct 64 bit for local dynamic + "R_390_TLS_IE32": 47 , # 32 bit address of GOT entry for + "R_390_TLS_IE64": 48 , # 64 bit address of GOT entry for + "R_390_TLS_IEENT": 49 , # 32 bit rel. offset to GOT entry for + "R_390_TLS_LE32": 50 , # 32 bit negated offset relative to + "R_390_TLS_LE64": 51 , # 64 bit negated offset relative to + "R_390_TLS_LDO32": 52 , # 32 bit offset relative to TLS + "R_390_TLS_LDO64": 53 , # 64 bit offset relative to TLS + "R_390_TLS_DTPMOD": 54 , # ID of module containing symbol. + "R_390_TLS_DTPOFF": 55 , # Offset in TLS block. + "R_390_TLS_TPOFF": 56 , # Negated offset in static TLS + "R_390_20": 57 , # Direct 20 bit. + "R_390_GOT20": 58 , # 20 bit GOT offset. + "R_390_GOTPLT20": 59 , # 20 bit offset to jump slot. + "R_390_TLS_GOTIE20": 60 , # 20 bit GOT offset for static TLS + "R_390_NUM": 61 , # + "R_CRIS_NONE": 0 , # + "R_CRIS_8": 1 , # + "R_CRIS_16": 2 , # + "R_CRIS_32": 3 , # + "R_CRIS_8_PCREL": 4 , # + "R_CRIS_16_PCREL": 5 , # + "R_CRIS_32_PCREL": 6 , # + "R_CRIS_GNU_VTINHERIT": 7 , # + "R_CRIS_GNU_VTENTRY": 8 , # + "R_CRIS_COPY": 9 , # + "R_CRIS_GLOB_DAT": 10 , # + "R_CRIS_JUMP_SLOT": 11 , # + "R_CRIS_RELATIVE": 12 , # + "R_CRIS_16_GOT": 13 , # + "R_CRIS_32_GOT": 14 , # + "R_CRIS_16_GOTPLT": 15 , # + "R_CRIS_32_GOTPLT": 16 , # + "R_CRIS_32_GOTREL": 17 , # + "R_CRIS_32_PLT_GOTREL": 18 , # + "R_CRIS_32_PLT_PCREL": 19 , # + "R_CRIS_NUM": 20 , # + "R_X86_64_NONE": 0 , # No reloc + "R_X86_64_64": 1 , # Direct 64 bit + "R_X86_64_PC32": 2 , # PC relative 32 bit signed + "R_X86_64_GOT32": 3 , # 32 bit GOT entry + "R_X86_64_PLT32": 4 , # 32 bit PLT address + "R_X86_64_COPY": 5 , # Copy symbol at runtime + "R_X86_64_GLOB_DAT": 6 , # Create GOT entry + "R_X86_64_JUMP_SLOT": 7 , # Create PLT entry + "R_X86_64_RELATIVE": 8 , # Adjust by program base + "R_X86_64_GOTPCREL": 9 , # 32 bit signed PC relative + "R_X86_64_32": 10 , # Direct 32 bit zero extended + "R_X86_64_32S": 11 , # Direct 32 bit sign extended + "R_X86_64_16": 12 , # Direct 16 bit zero extended + "R_X86_64_PC16": 13 , # 16 bit sign extended pc relative + "R_X86_64_8": 14 , # Direct 8 bit sign extended + "R_X86_64_PC8": 15 , # 8 bit sign extended pc relative + "R_X86_64_DTPMOD64": 16 , # ID of module containing symbol + "R_X86_64_DTPOFF64": 17 , # Offset in module's TLS block + "R_X86_64_TPOFF64": 18 , # Offset in initial TLS block + "R_X86_64_TLSGD": 19 , # 32 bit signed PC relative offset + "R_X86_64_TLSLD": 20 , # 32 bit signed PC relative offset + "R_X86_64_DTPOFF32": 21 , # Offset in TLS block + "R_X86_64_GOTTPOFF": 22 , # 32 bit signed PC relative offset + "R_X86_64_TPOFF32": 23 , # Offset in initial TLS block + "R_X86_64_PC64": 24 , # PC relative 64 bit + "R_X86_64_GOTOFF64": 25 , # 64 bit offset to GOT + "R_X86_64_GOTPC32": 26 , # 32 bit signed pc relative + "R_X86_64_GOT64": 27 , # 64-bit GOT entry offset + "R_X86_64_GOTPCREL64": 28 , # 64-bit PC relative offset + "R_X86_64_GOTPC64": 29 , # 64-bit PC relative offset to GOT + "R_X86_64_GOTPLT64": 30 , # like GOT64, says PLT entry needed + "R_X86_64_PLTOFF64": 31 , # 64-bit GOT relative offset + "R_X86_64_SIZE32": 32 , # Size of symbol plus 32-bit addend + "R_X86_64_SIZE64": 33 , # Size of symbol plus 64-bit addend + "R_X86_64_GOTPC32_TLSDESC": 34 , # GOT offset for TLS descriptor. + "R_X86_64_TLSDESC_CALL": 35 , # Marker for call through TLS + "R_X86_64_TLSDESC": 36 , # TLS descriptor. + "R_X86_64_IRELATIVE": 37 , # Adjust indirectly by program base + "R_X86_64_NUM": 38 , # + "R_MN10300_NONE": 0 , # No reloc. + "R_MN10300_32": 1 , # Direct 32 bit. + "R_MN10300_16": 2 , # Direct 16 bit. + "R_MN10300_8": 3 , # Direct 8 bit. + "R_MN10300_PCREL32": 4 , # PC-relative 32-bit. + "R_MN10300_PCREL16": 5 , # PC-relative 16-bit signed. + "R_MN10300_PCREL8": 6 , # PC-relative 8-bit signed. + "R_MN10300_GNU_VTINHERIT": 7 , # Ancient C++ vtable garbage... + "R_MN10300_GNU_VTENTRY": 8 , # ... collection annotation. + "R_MN10300_24": 9 , # Direct 24 bit. + "R_MN10300_GOTPC32": 10 , # 32-bit PCrel offset to GOT. + "R_MN10300_GOTPC16": 11 , # 16-bit PCrel offset to GOT. + "R_MN10300_GOTOFF32": 12 , # 32-bit offset from GOT. + "R_MN10300_GOTOFF24": 13 , # 24-bit offset from GOT. + "R_MN10300_GOTOFF16": 14 , # 16-bit offset from GOT. + "R_MN10300_PLT32": 15 , # 32-bit PCrel to PLT entry. + "R_MN10300_PLT16": 16 , # 16-bit PCrel to PLT entry. + "R_MN10300_GOT32": 17 , # 32-bit offset to GOT entry. + "R_MN10300_GOT24": 18 , # 24-bit offset to GOT entry. + "R_MN10300_GOT16": 19 , # 16-bit offset to GOT entry. + "R_MN10300_COPY": 20 , # Copy symbol at runtime. + "R_MN10300_GLOB_DAT": 21 , # Create GOT entry. + "R_MN10300_JMP_SLOT": 22 , # Create PLT entry. + "R_MN10300_RELATIVE": 23 , # Adjust by program base. + "R_MN10300_NUM": 24 , # + "R_M32R_NONE": 0 , # No reloc. + "R_M32R_16": 1 , # Direct 16 bit. + "R_M32R_32": 2 , # Direct 32 bit. + "R_M32R_24": 3 , # Direct 24 bit. + "R_M32R_10_PCREL": 4 , # PC relative 10 bit shifted. + "R_M32R_18_PCREL": 5 , # PC relative 18 bit shifted. + "R_M32R_26_PCREL": 6 , # PC relative 26 bit shifted. + "R_M32R_HI16_ULO": 7 , # High 16 bit with unsigned low. + "R_M32R_HI16_SLO": 8 , # High 16 bit with signed low. + "R_M32R_LO16": 9 , # Low 16 bit. + "R_M32R_SDA16": 10 , # 16 bit offset in SDA. + "R_M32R_GNU_VTINHERIT": 11 , # + "R_M32R_GNU_VTENTRY": 12 , # + "R_M32R_16_RELA": 33 , # Direct 16 bit. + "R_M32R_32_RELA": 34 , # Direct 32 bit. + "R_M32R_24_RELA": 35 , # Direct 24 bit. + "R_M32R_10_PCREL_RELA": 36 , # PC relative 10 bit shifted. + "R_M32R_18_PCREL_RELA": 37 , # PC relative 18 bit shifted. + "R_M32R_26_PCREL_RELA": 38 , # PC relative 26 bit shifted. + "R_M32R_HI16_ULO_RELA": 39 , # High 16 bit with unsigned low + "R_M32R_HI16_SLO_RELA": 40 , # High 16 bit with signed low + "R_M32R_LO16_RELA": 41 , # Low 16 bit + "R_M32R_SDA16_RELA": 42 , # 16 bit offset in SDA + "R_M32R_RELA_GNU_VTINHERIT": 43 , # + "R_M32R_RELA_GNU_VTENTRY": 44 , # + "R_M32R_REL32": 45 , # PC relative 32 bit. + "R_M32R_GOT24": 48 , # 24 bit GOT entry + "R_M32R_26_PLTREL": 49 , # 26 bit PC relative to PLT shifted + "R_M32R_COPY": 50 , # Copy symbol at runtime + "R_M32R_GLOB_DAT": 51 , # Create GOT entry + "R_M32R_JMP_SLOT": 52 , # Create PLT entry + "R_M32R_RELATIVE": 53 , # Adjust by program base + "R_M32R_GOTOFF": 54 , # 24 bit offset to GOT + "R_M32R_GOTPC24": 55 , # 24 bit PC relative offset to GOT + "R_M32R_GOT16_HI_ULO": 56 , # High 16 bit GOT entry with unsigned + "R_M32R_GOT16_HI_SLO": 57 , # High 16 bit GOT entry with signed + "R_M32R_GOT16_LO": 58 , # Low 16 bit GOT entry + "R_M32R_GOTPC_HI_ULO": 59 , # High 16 bit PC relative offset to + "R_M32R_GOTPC_HI_SLO": 60 , # High 16 bit PC relative offset to + "R_M32R_GOTPC_LO": 61 , # Low 16 bit PC relative offset to + "R_M32R_GOTOFF_HI_ULO": 62 , # High 16 bit offset to GOT + "R_M32R_GOTOFF_HI_SLO": 63 , # High 16 bit offset to GOT + "R_M32R_GOTOFF_LO": 64 , # Low 16 bit offset to GOT + "R_M32R_NUM": 256 , # Keep this the last entry. + "SHF_WRITE": (1 << 0) , # Writable + "SHF_ALLOC": (1 << 1) , # Occupies memory during execution + "SHF_EXECINSTR": (1 << 2) , # Executable + "SHF_MERGE": (1 << 4) , # Might be merged + "SHF_STRINGS": (1 << 5) , # Contains nul-terminated strings + "SHF_INFO_LINK": (1 << 6) , # `sh_info' contains SHT index + "SHF_LINK_ORDER": (1 << 7) , # Preserve order after combining + "SHF_OS_NONCONFORMING": (1 << 8) , # Non-standard OS specific handling + "SHF_GROUP": (1 << 9) , # Section is member of a group. + "SHF_TLS": (1 << 10) , # Section hold thread-local data. +# libelf.h constants +# ELF_C + "ELF_C_NULL": 0, + "ELF_C_READ": 1, + "ELF_C_WRITE": 2, + "ELF_C_CLR": 3, + "ELF_C_SET": 4, + "ELF_C_FDDONE": 5, + "ELF_C_FDREAD": 6, + "ELF_C_RDWR": 7, + "ELF_C_NUM": 8, +# ELF_K + "ELF_K_NONE": 0, + "ELF_K_AR": 1, + "ELF_K_COFF": 2, + "ELF_K_ELF": 3, + "ELF_K_NUM": 4, +# ELF_T + "ELF_T_BYTE": 00, + "ELF_T_ADDR": 01, + "ELF_T_DYN": 02, + "ELF_T_EHDR": 03, + "ELF_T_HALF": 04, + "ELF_T_OFF": 05, + "ELF_T_PHDR": 06, + "ELF_T_RELA": 07, + "ELF_T_REL": 8, + "ELF_T_SHDR": 9, + "ELF_T_SWORD": 10, + "ELF_T_SYM": 11, + "ELF_T_WORD": 12, + "ELF_T_SXWORD": 13, + "ELF_T_XWORD": 14, + "ELF_T_VDEF": 15, + "ELF_T_VNEED": 16, + "ELF_T_NUM": 17, +# ELF_F (ELF flags) + "ELF_F_DIRTY": 0x1 , # + "ELF_F_LAYOUT": 0x4 , # + "ELF_F_LAYOUT_OVERLAP": 0x10000000 , # +} + +# Now lets generate constants for all + +g = globals() + +for c in _consts: + g[c] = _consts[c] + +__all__ = _consts.keys() + +# TODO: Move these to the macros module + +#elf.h + +# Macro functions + +#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) + +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) # Reverse order! + +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) # Reverse order! + +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) # Reverse order! +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) + +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char) (info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) +#define ELF64_M_SYM(info) ELF32_M_SYM (info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) + +#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) + +#libelf.h diff --git a/tools/esp_app_trace/pylibelf/iterators/__init__.py b/tools/esp_app_trace/pylibelf/iterators/__init__.py new file mode 100644 index 000000000..437a7118c --- /dev/null +++ b/tools/esp_app_trace/pylibelf/iterators/__init__.py @@ -0,0 +1,216 @@ +import sys +import os +from .. import * +from ..constants import * +from ..types import * +from ..util import * +from ctypes import * + +def sections(elf, **kwargs): + i = None + ndx = 0 # we skip the first null section + if 'info' in kwargs: + if (isinstance(kwargs['info'], Elf_Scn)): + info = elf_ndxscn(kwargs['info']) + else: + info = kwargs['info'] + else: + info = None + while 1: + i = elf_nextscn(elf, i) + ndx += 1 + + if (not bool(i)): + break + + try: + if ('name' in kwargs and section_name(elf, i) != kwargs['name']): + continue + + if ('type' in kwargs and section_type(elf, i) != kwargs['type']): + continue + + if ('link' in kwargs and section_link(elf, i) != kwargs['link']): + continue + + if (info != None and section_hdr(elf, i).sh_info != info): + continue + except ValueError: + print "Error iterating over section ", i + continue + + if ('ndx' in kwargs and kwargs['ndx']): + yield (ndx, i.contents) + else: + yield i.contents + + +def shdrs(elf): + i = None + while 1: + i = elf_nextscn(elf, i) + if (not bool(i)): + break + + yield select(elf, 'getshdr')(i.contents).contents + +def phdrs(elf): + phdrTbl = select(elf, "getphdr")(elf) + ehdr = select(elf, "getehdr")(elf).contents + phdrCnt = ehdr.e_phnum + + for i in xrange(0, phdrCnt): + yield phdrTbl[i] + +def data(elf_scn): + i = None + while 1: + i = elf_getdata(elf_scn, i) + + if (not bool(i)): + break + + yield i.contents + +def strings(v): + if (isinstance(v, Elf_Data)): + strtab_data = v + size = strtab_data.d_size + buf = cast(strtab_data.d_buf, POINTER(c_char)) + start = 0; + while start < size: + end = start; + while buf[end] != '\x00': end += 1 + yield (strtab_data.d_off + start, buf[start:end]) + + start = end+1 + elif (isinstance(v, Elf_Scn)): + for d in data(v): + strtab_data = d + size = strtab_data.d_size + buf = cast(strtab_data.d_buf, POINTER(c_char)) + start = 0; + while start < size: + end = start; + while buf[end] != '\x00': end += 1 + yield (strtab_data.d_off + start, buf[start:end]) + + start = end+1 + + +def arr_iter(data, itemT, ind = False): + size = data.d_size + + if size % sizeof(itemT) != 0: + raise Exception("Data size not a multiple of symbol size!") + + buf = cast(data.d_buf, POINTER(itemT)) + nelems = size / sizeof(itemT) + + for i in xrange(0, nelems): + if ind: + yield (i, buf[i]) + else: + yield buf[i] + +def syms(elf, v = None): + symT = Elf32_Sym if (is32(elf)) else Elf64_Sym + if v == None: + for s in sections(elf): + hdr = section_hdr(elf, s) + + if (hdr.sh_type != SHT_SYMTAB and hdr.sh_type != SHT_DYNSYM): + continue + + for d in data(s): + for (ind, sym) in arr_iter(d, symT, True): + yield (ind, sym) + elif isinstance(v, Elf_Scn): + for d in data(v): + for (ind, sym) in arr_iter(d, symT, True): + yield (ind, sym) + else: + assert isinstance(v, Elf_Data) + for (ind, sym) in arr_iter(v, symT, True): + yield (ind, sym) + +def rels(elf, **kwargs): + relT = Elf32_Rel if (is32(elf)) else Elf64_Rel + if 'section' in kwargs: + secl = sections(elf, type = SHT_REL, info = kwargs['section']) + else: + secl = sections(elf, type = SHT_REL) + + + if 'range' in kwargs: + for scn in secl: + for d in data(scn): + for rel in arr_iter(d, relT): + if (rel.r_offset >= kwargs['range'][0] and + rel.r_offset < kwargs['range'][1]): + yield (rel, section_hdr(elf, scn).sh_link) + else: + for scn in secl: + for d in data(scn): + for rel in arr_iter(d, relT): + yield (rel, section_hdr(elf, scn).sh_link) + +def relas(elf, **kwargs): + relT = Elf32_Rela if (is32(elf)) else Elf64_Rela + if 'section' in kwargs: + scn = kwargs['section'] + if (type(scn) == str): scn = list(sections(elf, name=scn))[0] + if (isinstance(scn, Elf_Scn)): scn = elf_ndxscn(byref(scn)) + secl = list(sections(elf, type = SHT_RELA, info = scn)) + else: + secl = list(sections(elf, type = SHT_RELA)) + + if 'range' in kwargs: + for scn in secl: + for d in data(scn): + for rel in arr_iter(d, relT): + if (rel.r_offset + rel.r_addend >= kwargs['range'][0] and + rel.r_offset + rel.r_addend < kwargs['range'][1]): + yield (rel, section_hdr(elf, scn).sh_link) + else: + addSecId = kwargs['withSectionId']==True \ + if 'withSectionId' in kwargs \ + else False + if not addSecId: + for scn in secl: + for d in data(scn): + for rel in arr_iter(d, relT): + yield (rel, section_hdr(elf, scn).sh_link) + else: + for scn in secl: + for d in data(scn): + for rel in arr_iter(d, relT): + yield (rel, section_hdr(elf, scn).sh_info) + +def getOnlyData(scn): + d = elf_getdata(scn, None); + assert bool(elf_getdata(scn, d)) == False + return d + +def dyns(elf): + relT = Elf64_Dyn + for scn in sections(elf, name=".dynamic"): + for d in data(scn): + for dyn in arr_iter(d, relT): + yield dyn + +def elfs(fname): + fd = os.open(fname, os.O_RDONLY) + ar = elf_begin(fd, ELF_C_READ, None) + + i = None + while 1: + i = elf_begin(fd, ELF_C_READ, ar) + if (not bool(i)): + break + + yield i + + elf_end(ar) + os.close(fd) + diff --git a/tools/esp_app_trace/pylibelf/macros/__init__.py b/tools/esp_app_trace/pylibelf/macros/__init__.py new file mode 100644 index 000000000..d51a8d93f --- /dev/null +++ b/tools/esp_app_trace/pylibelf/macros/__init__.py @@ -0,0 +1,55 @@ +def ELF32_R_SYM(i): + if type(i) == str: + assert(len(i) == 1) # Single char + i = ord(i) + return i >> 8 + +def ELF32_R_TYPE(i): + if type(i) == str: + assert(len(i) == 1) # Single char + i = ord(i) + return i % 256 # Lowest 8 bits + +def ELF32_R_INFO(sym, typ): + return (((sym) << 8) + typ % 256) + +def ELF64_R_SYM(i): + if type(i) == str: + assert(len(i) == 1) # Single char + i = ord(i) + return i >> 32 + +def ELF64_R_TYPE(i): + if type(i) == str: + assert(len(i) == 1) # Single char + i = ord(i) + return i & 0xffffffffL + +def ELF64_R_INFO(sym, typ): + return ((sym << 32) + (typ & 0xffffffffL)) + +# symbol st_info + +def ELF32_ST_BIND(val): + if type(val) == str: + assert(len(val) == 1) # Single char + val = ord(val) + return val >> 4 + +def ELF32_ST_TYPE(val): + if type(val) == str: + assert(len(val) == 1) # Single char + val = ord(val) + return val & 0xf + +def ELF32_ST_INFO(bind, type): + return (((bind) << 4) + ((type) & 0xf)) + +def ELF64_ST_BIND(val): + return ELF32_ST_BIND(val) + +def ELF64_ST_TYPE(val): + return ELF32_ST_TYPE(val) + +def ELF64_ST_INFO(bind, type): + return ELF32_ST_INFO(bind, type) diff --git a/tools/esp_app_trace/pylibelf/types/__init__.py b/tools/esp_app_trace/pylibelf/types/__init__.py new file mode 100644 index 000000000..cc838d2f0 --- /dev/null +++ b/tools/esp_app_trace/pylibelf/types/__init__.py @@ -0,0 +1,274 @@ +from ctypes import * +from ..constants import EI_NIDENT + +# Obtained from /usr/lib/elf.h + +# Type for a 16-bit quantity. +Elf32_Half = c_uint16 +Elf64_Half = c_uint16 + +# Types for signed and unsigned 32-bit quantities. +Elf32_Word = c_uint32 +Elf32_Sword = c_int32 +Elf64_Word = c_uint32 +Elf64_Sword = c_int32 + +# Types for signed and unsigned 64-bit quantities. +Elf32_Xword = c_uint64 +Elf32_Sxword = c_int64 +Elf64_Xword = c_uint64 +Elf64_Sxword = c_int64 + +# Type of addresses. +Elf32_Addr = c_uint32 +Elf64_Addr = c_uint64 + +# Type of file offsets. +Elf32_Off = c_uint32 +Elf64_Off = c_uint64 + +# Type for section indices, which are 16-bit quantities. +Elf32_Section = c_uint16 +Elf64_Section = c_uint16 + +# Type for version symbol information. +Elf32_Versym = Elf32_Half +Elf64_Versym = Elf64_Half + +# The ELF file header. This appears at the start of every ELF file. + +Elf_IdentT = c_char * EI_NIDENT + +Elf_Cmd = c_int + +class _ElfStructure(Structure): + def __str__(self): + return self.__class__.__name__ + '(' + \ + ','.join([field[0] + '=' + str(getattr(self, field[0])) for field in self._fields_]) + ')' + +class _ElfUnion(Union): + def __str__(self): + return self.__class__.__name__ + '(' + \ + ','.join([field[0] + '=' + str(getattr(self, field[0])) for field in self._fields_]) + ')' + +# Libelf opaque handles +class Elf(_ElfStructure): + _fields_ = [] +class Elf_Scn(_ElfStructure): + _fields_ = [] + +class Elf_Data(_ElfStructure): + _fields_ = [ + ('d_buf', c_void_p), + ('d_type', c_int), + ('d_size', c_size_t), + ('d_off', c_size_t), + ('d_align', c_size_t), + ('d_version', c_uint) + ] + +ElfP = POINTER(Elf) +Elf_ScnP = POINTER(Elf_Scn) +Elf_DataP = POINTER(Elf_Data) + +class Elf32_Ehdr(_ElfStructure): + _fields_ = [ + ('e_ident', Elf_IdentT ), # Magic number and other info + ('e_type', Elf32_Half ), # Object file type + ('e_machine', Elf32_Half ), # Architecture + ('e_version', Elf32_Word ), # Object file version + ('e_entry', Elf32_Addr ), # Entry point virtual address + ('e_phoff', Elf32_Off), # Program header table file offset + ('e_shoff', Elf32_Off), # Section header table file offset + ('e_flags', Elf32_Word ), # Processor-specific flags + ('e_ehsize', Elf32_Half ), # ELF header size in bytes + ('e_phentsize', Elf32_Half ), # Program header table entry size + ('e_phnum', Elf32_Half ), # Program header table entry count + ('e_shentsize', Elf32_Half ), # Section header table entry size + ('e_shnum', Elf32_Half ), # Section header table entry count + ('e_shstrndx', Elf32_Half ), # Section header string table index + ] + +class Elf64_Ehdr(_ElfStructure): + _fields_ = [ + ('e_ident', Elf_IdentT ), # Magic number and other info + ('e_type', Elf64_Half ), # Object file type + ('e_machine', Elf64_Half ), # Architecture + ('e_version', Elf64_Word ), # Object file version + ('e_entry', Elf64_Addr ), # Entry point virtual address + ('e_phoff', Elf64_Off), # Program header table file offset + ('e_shoff', Elf64_Off), # Section header table file offset + ('e_flags', Elf64_Word ), # Processor-specific flags + ('e_ehsize', Elf64_Half ), # ELF header size in bytes + ('e_phentsize', Elf64_Half ), # Program header table entry size + ('e_phnum', Elf64_Half ), # Program header table entry count + ('e_shentsize', Elf64_Half ), # Section header table entry size + ('e_shnum', Elf64_Half ), # Section header table entry count + ('e_shstrndx', Elf64_Half ), # Section header string table index + ] + +class Elf32_Shdr(_ElfStructure): + _fields_ = [ + ('sh_name', Elf32_Word), # Section name (string tbl index) + ('sh_type', Elf32_Word), # Section type + ('sh_flags', Elf32_Word), # Section flags + ('sh_addr', Elf32_Addr), # Section virtual addr at execution + ('sh_offset', Elf32_Off), # Section file offset + ('sh_size', Elf32_Word), # Section size in bytes + ('sh_link', Elf32_Word), # Link to another section + ('sh_info', Elf32_Word), # Additional section information + ('sh_addralign', Elf32_Word), # Section alignment + ('sh_entsize', Elf32_Word), # Entry size if section holds table + ] + +class Elf64_Shdr(_ElfStructure): + _fields_ = [ + ('sh_name', Elf64_Word), # Section name (string tbl index) + ('sh_type', Elf64_Word), # Section type + ('sh_flags', Elf64_Xword), # Section flags + ('sh_addr', Elf64_Addr), # Section virtual addr at execution + ('sh_offset', Elf64_Off), # Section file offset + ('sh_size', Elf64_Xword), # Section size in bytes + ('sh_link', Elf64_Word), # Link to another section + ('sh_info', Elf64_Word), # Additional section information + ('sh_addralign', Elf64_Xword), # Section alignment + ('sh_entsize', Elf64_Xword), # Entry size if section holds table + ] + +class Elf32_Phdr(_ElfStructure): + _fields_ = [ + ('p_type', Elf32_Word), # Segment type + ('p_offset', Elf32_Off), # Segment file offset + ('p_vaddr', Elf32_Addr), # Segment virtual address + ('p_paddr', Elf32_Addr), # Segment physical address + ('p_filesz', Elf32_Word), # Segment size in file + ('p_memsz', Elf32_Word), # Segment size in memory + ('p_flags', Elf32_Word), # Segment flags + ('p_align', Elf32_Word), # Segment alignment + ] + +class Elf64_Phdr(_ElfStructure): + _fields_ = [ + ('p_type', Elf64_Word), # Segment type + ('p_flags', Elf64_Word), # Segment flags + ('p_offset', Elf64_Off), # Segment file offset + ('p_vaddr', Elf64_Addr), # Segment virtual address + ('p_paddr', Elf64_Addr), # Segment physical address + ('p_filesz', Elf64_Xword), # Segment size in file + ('p_memsz', Elf64_Xword), # Segment size in memory + ('p_align', Elf64_Xword), # Segment alignment + ] + +# /* Symbol table entry. */ +class Elf32_Sym(_ElfStructure): + _fields_ = [ + ('st_name', Elf32_Word), # Symbol name (string tbl index) + ('st_value', Elf32_Addr), # Symbol value + ('st_size', Elf32_Word), # Symbol size + ('st_info', c_char), # Symbol type and binding + ('st_other', c_char), # Symbol visibility + ('st_shndx', Elf32_Section), # Section index + ] + +class Elf64_Sym(_ElfStructure): + _fields_ = [ + ('st_name', Elf64_Word), # Symbol name (string tbl index) + ('st_info', c_char), # Symbol type and binding + ('st_other', c_char), # Symbol visibility + ('st_shndx', Elf64_Section), # Section index + ('st_value', Elf64_Addr), # Symbol value + ('st_size', Elf64_Xword), # Symbol size + ] + +#/* The syminfo section if available contains additional information about +# every dynamic symbol. */ + +class Elf32_Syminfo(_ElfStructure): + _fields_ = [ + ('si_boundto', Elf32_Half), # Direct bindings, symbol bound to + ('si_flags', Elf32_Half), # Per symbol flags + ] + +class Elf64_Syminfo(_ElfStructure): + _fields_ = [ + ('si_boundto', Elf64_Half), # Direct bindings, symbol bound to + ('si_flags', Elf64_Half), # Per symbol flags + ] + +# /* Relocation table entry without addend (in section of type SHT_REL). */ + +class Elf32_Rel(_ElfStructure): + _fields_ = [ + ('r_offset', Elf32_Addr), # Address + ('r_info', Elf32_Word), # Relocation type and symbol index + ] + +class Elf64_Rel(_ElfStructure): + _fields_ = [ + ('r_offset', Elf64_Addr), # Address + ('r_info', Elf64_Xword), # Relocation type and symbol index + ] + +# # Relocation table entry with addend (in section of type SHT_RELA). + +class Elf32_Rela(_ElfStructure): + _fields_ = [ + ('r_offset', Elf32_Addr), # Address + ('r_info', Elf32_Word), # Relocation type and symbol index + ('r_addend', Elf32_Sword), # Addend + ] + +class Elf64_Rela(_ElfStructure): + _fields_ = [ + ('r_offset', Elf64_Addr), # Address + ('r_info', Elf64_Xword), # Relocation type and symbol index + ('r_addend', Elf64_Sxword), # Addend + ] + +time_t = c_int64 +uid_t = c_int32 +gid_t = c_int32 +mode_t = c_int32 +off_t = c_int64 + +class Elf_Arhdr(_ElfStructure): + _fields_ = [ + ('ar_name', c_char_p), + ('ar_date', time_t), + ('ar_uid', uid_t), + ('ar_gid', gid_t), + ('ar_mode', mode_t), + ('ar_size', off_t), + ('ar_fmag', POINTER(c_char)), + ] + +class _Elf64_DynUnion(_ElfUnion): + _fields_ = [ + ('d_val', Elf64_Xword), + ('d_ptr', Elf64_Addr), + ] + +class Elf64_Dyn(_ElfStructure): + _fields_ = [ + ('d_tag', Elf64_Xword), + ('d_un', _Elf64_DynUnion), + ] + +# GNU Extensions +class Elf64_Verneed(_ElfStructure): + _fields_ = [ + ('vn_version', Elf64_Half), + ('vn_cnt', Elf64_Half), + ('vn_file', Elf64_Word), + ('vn_aux', Elf64_Word), + ('vn_next', Elf64_Word), + ] + +class Elf64_Vernaux(_ElfStructure): + _fields_ = [ + ('vna_hash', Elf64_Word), + ('vna_flags', Elf64_Half), + ('vna_other', Elf64_Half), + ('vna_name', Elf64_Word), + ('vna_next', Elf64_Word), + ] diff --git a/tools/esp_app_trace/pylibelf/util/__init__.py b/tools/esp_app_trace/pylibelf/util/__init__.py new file mode 100644 index 000000000..5eb472a4f --- /dev/null +++ b/tools/esp_app_trace/pylibelf/util/__init__.py @@ -0,0 +1,38 @@ +from .. import * +from ..types import * +from ..constants import * +from ctypes import * +import os + +def _class(elf): return ord(elf_getident(elf, None).contents[EI_CLASS]) + +def is32(elf): return _class(elf) == ELFCLASS32 +def is64(elf): return _class(elf) == ELFCLASS64 + +def select(elf, fname): + if is32(elf): + return globals()['elf32_' + fname] + else: + return globals()['elf64_' + fname] + +def section_name(elfP, secP): + shstrndx = c_size_t() + r = elf_getshstrndx(elfP, byref(shstrndx)) + shdr = select(elfP, 'getshdr')(secP) + return elf_strptr(elfP, shstrndx, shdr.contents.sh_name) + +def section_type(elfP, secP): + return select(elfP, 'getshdr')(secP).contents.sh_type + +def section_link(elfP, secP): + return select(elfP, 'getshdr')(secP).contents.sh_link + +def section_hdr(elfP, secP): + return select(elfP, 'getshdr')(secP).contents + +def open_elf(fname): + fd = os.open(fname, os.O_RDONLY) + return elf_begin(fd, ELF_C_READ, None) + +def sym_name(elf, scn, sym): + return elf_strptr(elf, section_link(elf, scn), sym.st_name) diff --git a/tools/esp_app_trace/pylibelf/util/syms/__init__.py b/tools/esp_app_trace/pylibelf/util/syms/__init__.py new file mode 100644 index 000000000..ac7267e18 --- /dev/null +++ b/tools/esp_app_trace/pylibelf/util/syms/__init__.py @@ -0,0 +1,58 @@ +from .. import * +from ...types import * +from ...iterators import * + +def defined(s): return s.st_shndx != SHN_UNDEF + +def defines(elf, symN): + s = findSymbol(elf, symN) + print elf, symN, s + if s != None: + print s.st_shndx, s.st_name + return s != None and defined(s[1]) + +def derefSymbol(elf, s): + assert defined(s) + if s.st_shndx == SHN_ABS: + raise Exception("NYI") + else: + scn = elf_getscn(elf, s.st_shndx) + shdr = section_hdr(elf, scn); + off = 0 + base = shdr.sh_addr if shdr.sh_addr != 0 else 0 + start = s.st_value + end = s.st_value + s.st_size + r = '' + for d in data(scn): + if start >= end: break; + off = base + d.d_off + if start >= off and start < off + d.d_size: + c = cast(d.d_buf, POINTER(c_char)) + l = min(off + d.d_size, end) - start + r += c[start- off : start - off + l] + start += l + + return r + +def derefSymbolFull(elf, s): + """ Given an elf file and a Elf{32/64}_Sym defined in the elf file, + return a tuple with the contents of memory refered to by the symbol, + and any Rel's and Rela's inside that memory. + """ + assert (defined(s)) + contents = derefSymbol(elf, s) + relL = list(rels(elf, section=s.st_shndx, \ + range=(s.st_value, s.st_size + s.st_value))) + relaL = list(relas(elf, section=s.st_shndx, \ + range=(s.st_value, s.st_size + s.st_value))) + return (contents, relL, relaL) + +# Given a symbol name return the symbol and section in which it occurs +def findSymbol(elf, s): + for scn in sections(elf, type=SHT_SYMTAB): + strndx = section_link(elf, scn) + for d in data(scn): + for (ind, sym) in syms(elf, d): + if s == elf_strptr(elf, strndx, sym.st_name): + return (scn, sym) + return None diff --git a/tools/unit-test-app/sdkconfig b/tools/unit-test-app/sdkconfig index 2c73a45ca..44b599b4a 100644 --- a/tools/unit-test-app/sdkconfig +++ b/tools/unit-test-app/sdkconfig @@ -106,11 +106,17 @@ CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 CONFIG_MEMMAP_SMP=y # CONFIG_MEMMAP_TRACEMEM is not set +# CONFIG_MEMMAP_TRACEMEM_TWOBANKS is not set +# CONFIG_ESP32_TRAX is not set CONFIG_TRACEMEM_RESERVE_DRAM=0x0 # CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set # CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y # CONFIG_ESP32_ENABLE_COREDUMP is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +# CONFIG_ESP32_APPTRACE_DEST_UART is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +# CONFIG_ESP32_APPTRACE_ENABLE is not set # CONFIG_TWO_MAC_ADDRESS_FROM_EFUSE is not set CONFIG_FOUR_MAC_ADDRESS_FROM_EFUSE=y CONFIG_NUMBER_OF_MAC_ADDRESS_GENERATED_FROM_EFUSE=4