| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef BASE_PROFILER_CHROME_UNWIND_INFO_ANDROID_H_ |
| #define BASE_PROFILER_CHROME_UNWIND_INFO_ANDROID_H_ |
| |
| #include <stdint.h> |
| |
| #include "base/base_export.h" |
| #include "base/containers/span.h" |
| |
| namespace base { |
| |
| // Represents each entry in the function table (i.e. the second level of the |
| // function address table). |
| struct FunctionTableEntry { |
| // The offset into the 128kb page containing this function. Indexed by bits |
| // 1-16 of the pc offset from the start of the text section. |
| uint16_t function_start_address_page_instruction_offset; |
| |
| // The byte index of the first offset for the function in the function |
| // offset table. |
| uint16_t function_offset_table_byte_index; |
| }; |
| |
| // The header at the start of the unwind info resource, with offsets/sizes for |
| // the tables contained within the resource. |
| // |
| // The unwind info provides 4 tables which can translate an instruction address |
| // to a set of unwind instructions to unwind the function frame the instruction |
| // belongs to. |
| // |
| // `page_table` and `function_table` together locates which function the |
| // instruction address belongs to given an instruction address. |
| // |
| // `function_offset_table` and `unwind_instruction_table` together locates |
| // which sets of unwind instructions to execute given the function info |
| // obtained from `page_table` and `function_table`, and the offset between the |
| // instruction address and function start address. |
| // |
| // Design Doc: |
| // https://docs.google.com/document/d/1IYTmGCJZoiQ242xPUZX1fATD6ivsjU1TAt_fPv74ocs/edit?usp=sharing |
| struct BASE_EXPORT ChromeUnwindInfoHeaderAndroid { |
| // The offset in bytes from the start of the unwind info resource to the |
| // page table (i.e. the first level of the function address table). The page |
| // table represents discrete 128kb 'pages' of memory in the text section, |
| // each of which contains functions. The page table is indexed by bits 17 |
| // and greater of the pc offset from the start of the text section. |
| // Indexing into page_table produces an index of function_table. |
| uint32_t page_table_byte_offset; |
| uint32_t page_table_entries; |
| |
| // The offset in bytes from the start of the unwind info resource to the |
| // function table (i.e. the second level of the function address table). The |
| // function table represents the individual functions within a 128kb page. |
| // Each function is represented as a `FunctionTableEntry`. The relevant entry |
| // for a pc offset from the start of the text section is the one with the |
| // largest function_start_address_page_instruction_offset <= (pc_offset >> 1) |
| // & 0xffff. |
| uint32_t function_table_byte_offset; |
| uint32_t function_table_entries; |
| |
| // The offset in bytes from the start of the unwind info resource to the |
| // function offset table. The function offset table represents the pc |
| // offsets from the start of each function along with indices into the |
| // unwind instructions for the offsets. The pc offsets and unwind indices |
| // are represented as (ULEB128, ULEB128) pairs in decreasing order of |
| // offset. Distinct sequences of (offset, index) pairs are concatenated in |
| // the table. |
| uint32_t function_offset_table_byte_offset; |
| uint32_t function_offset_table_size_in_bytes; |
| |
| // The offset in bytes from the start of the unwind info resource to the |
| // unwind instruction table. The unwind instruction table represents |
| // distinct sequences of ARM compact unwind instructions[1] used across all |
| // functions in Chrome. The compact unwind instruction is a byte-oriented |
| // variable length encoding so is indexed by byte position. |
| // 1. See Exception handling ABI for the ARM architecture ABI, §9.3. |
| // https://developer.arm.com/documentation/ihi0038/b. |
| uint32_t unwind_instruction_table_byte_offset; |
| uint32_t unwind_instruction_table_size_in_bytes; |
| }; |
| |
| struct BASE_EXPORT ChromeUnwindInfoAndroid { |
| ChromeUnwindInfoAndroid(span<const uint8_t> unwind_instruction_table, |
| span<const uint8_t> function_offset_table, |
| span<const FunctionTableEntry> function_table, |
| span<const uint32_t> page_table); |
| ~ChromeUnwindInfoAndroid(); |
| ChromeUnwindInfoAndroid(const ChromeUnwindInfoAndroid& other); |
| ChromeUnwindInfoAndroid& operator=(const ChromeUnwindInfoAndroid& other); |
| |
| ChromeUnwindInfoAndroid(ChromeUnwindInfoAndroid&& other); |
| ChromeUnwindInfoAndroid& operator=(ChromeUnwindInfoAndroid&& other); |
| |
| // Unwind instruction table is expected to have following memory layout: |
| // +-----------------------------+ |
| // | <--1 byte---> | |
| // +-----------------------------+ |
| // | pop {r4, r5, lr} | <- FUNC1 offset 10 |
| // +-----------------------------+ |
| // | add sp, 16 | <- FUNC1 offset 4 |
| // +-----------------------------+ |
| // | mov pc, lr | <- FUNC1 offset 0 (COMPLETE) |
| // +-----------------------------+ |
| // | pop {r4, r11} [byte 1/2] | <- FUNC2 offset 8 |
| // +-----------------------------+ |
| // | pop {r4, r11} [byte 2/2] | |
| // +-----------------------------+ |
| // | ... | |
| // +-----------------------------+ |
| // Because we are unwinding the function, the next unwind instruction to |
| // execute always has smaller function offset. |
| // The function offsets are often discontinuous as not all instructions in |
| // the function have corresponding unwind instructions. |
| // |
| // See Exception handling ABI for the ARM architecture ABI, §9.3. |
| // https://developer.arm.com/documentation/ihi0038/b. |
| // for details in unwind instruction encoding. |
| // Only following instruction encodings are handled: |
| // - 00xxxxxx |
| // - 01xxxxxx |
| // - 1000iiii iiiiiiii |
| // - 1001nnnn |
| // - 10100nnn |
| // - 10101nnn |
| // - 10110000 |
| // - 10110010 uleb128 |
| span<const uint8_t> unwind_instruction_table; |
| |
| // Function offset table is expected to have following memory layout: |
| // +---------------------+---------------------+ |
| // | <-----ULEB128-----> | <-----ULEB128-----> | |
| // +---------------------+---------------------+ |
| // | Offset | Unwind Index | |
| // +---------------------+---------------------+----- |
| // | 8 | XXX | | |
| // +---------------------+---------------------+ | |
| // | 3 | YYY |Function 1 |
| // +---------------------+---------------------+ | |
| // | 0 | ZZZ | | |
| // +---------------------+---------------------+----- |
| // | 5 | AAA | | |
| // +---------------------+---------------------+Function 2 |
| // | 0 | BBB | | |
| // +---------------------+---------------------+----- |
| // | ... | .... | |
| // +---------------------+---------------------+ |
| // The function offset table contains [offset, unwind index] pairs, where |
| // - offset: offset from function start address of an instruction that affects |
| // the unwind state, measured in two-byte instructions. |
| // - unwind index: unwind instruction location in unwind instruction table. |
| // |
| // Note: |
| // - Each function always ends at 0 offset, which corresponds to a terminal |
| // instruction in unwind instruction table. |
| // - Within each function section, offset strictly decreases. By doing so, |
| // each function's own terminal instruction will serve as termination |
| // condition when searching in the table. |
| span<const uint8_t> function_offset_table; |
| |
| // The function table represents the individual functions within a 128kb page. |
| // The relevant entry for an instruction offset from the start of the text |
| // section is the one with the largest function_start_address_page_offset <= |
| // instruction_byte_offset_from_text_section_start. |
| // |
| // Function table is expected to have following memory layout: |
| // +--------------------+--------------------+ |
| // | <-----2 byte-----> | <-----2 byte-----> | |
| // +--------------------+--------------------+ |
| // | Page Offset | Offset Table Index | |
| // +--------------------+--------------------+----- |
| // | 10 | XXX | | |
| // +--------------------+--------------------+ | |
| // | ... | ... |Page 0x100 |
| // +--------------------+--------------------+ | |
| // | 65500 | ZZZ | | |
| // +--------------------+--------------------+----- |
| // | 200 | AAA | | |
| // +--------------------+--------------------+ | |
| // | ... | ... |Page 0x101 |
| // +--------------------+--------------------+ | |
| // | 65535 | BBB | | |
| // +--------------------+--------------------+----- |
| // |
| // Note: |
| // - Within each page, `Page Offset` strictly increases. |
| // - Each `FunctionTableEntry` represents a function where the start |
| // address falls into the page memory address range. |
| span<const FunctionTableEntry> function_table; |
| |
| // The page table represents discrete 128kb 'pages' of memory in the text |
| // section, each of which contains functions. The page table is indexed by |
| // bits 17 and greater of the pc offset from the start of the text section. |
| // Indexing into page_table produces an index of function_table. |
| // |
| // The page table is expected to have following memory layout: |
| // +----------------+ |
| // | <-- 4 byte --> | |
| // +----------------+ |
| // | 0 | |
| // +----------------+ |
| // | 18 | |
| // +----------------+ |
| // | 18 | |
| // +----------------+ |
| // | 80 | |
| // +----------------+ |
| // | ... | |
| // +----------------+ |
| // Note: |
| // - The page start instructions in page table non-strictly increases, i.e |
| // empty page is allowed. |
| span<const uint32_t> page_table; |
| }; |
| |
| // Creates `ChromeUnwindInfoAndroid` struct based on binary `data` assuming |
| // `data` starts with `ChromeUnwindInfoHeaderAndroid`. |
| BASE_EXPORT ChromeUnwindInfoAndroid |
| CreateChromeUnwindInfoAndroid(span<const uint8_t> data); |
| |
| } // namespace base |
| |
| #endif // BASE_PROFILER_CHROME_UNWIND_INFO_ANDROID_H_ |