Skip to content

Commit eac951f

Browse files
kylewanginchinarvql
authored andcommitted
fix: tpbase offset extraction and main rebase
1 parent 0b3bbff commit eac951f

3 files changed

Lines changed: 70 additions & 54 deletions

File tree

agent/crates/trace-utils/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,11 @@ pub struct LuaRuntimeInfo {
143143
#[cfg(feature = "enterprise")]
144144
#[repr(C)]
145145
pub struct PythonUnwindInfo {
146-
pub thread_state_address: u64,
146+
pub auto_tls_key_addr: u64,
147+
pub version: u16,
148+
pub tsd_info: TSDInfo,
147149
pub offsets_id: u8,
150+
pub _padding: [u8; 5],
148151
}
149152

150153
#[cfg(feature = "enterprise")]

agent/crates/trace-utils/src/trace_utils.h

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ typedef struct {
171171
unwind_entry_t entries[UNWIND_ENTRIES_PER_SHARD];
172172
} unwind_entry_shard_t;
173173

174-
#if defined(DF_ENTERPRISE)
174+
/**
175+
* Thread Specific Data info for accessing per-thread PyThreadState.
176+
*/
175177
typedef struct {
176178
/**
177179
* Offset from thread pointer base (TPBASE) to TSD storage
@@ -187,27 +189,13 @@ typedef struct {
187189
uint8_t indirect;
188190
} tsd_info_t;
189191

192+
#if defined(DF_ENTERPRISE)
190193
typedef struct {
191-
/**
192-
* Address of autoTLSkey variable in Python runtime
193-
*/
194194
uint64_t auto_tls_key_addr;
195-
/**
196-
* Python version encoded as 0xMMmm (e.g., 0x030A for 3.10)
197-
*/
198195
uint16_t version;
199-
/**
200-
* Thread Specific Data info for multi-threading support
201-
*/
202196
tsd_info_t tsd_info;
203-
/**
204-
* ID for looking up python_offsets in the offsets map
205-
*/
206197
uint8_t offsets_id;
207-
/**
208-
* Padding for alignment
209-
*/
210-
uint8_t _padding[5];
198+
uint8_t padding[5];
211199
} python_unwind_info_t;
212200
#endif
213201

@@ -721,6 +709,11 @@ extern void python_unwind_table_unload(python_unwind_table_t *table, uint32_t pi
721709

722710
int32_t read_offset_of_stack_in_task_struct(void);
723711

712+
/**
713+
* C-callable function to read TPBASE offset
714+
*/
715+
int64_t read_tpbase_offset(void);
716+
724717
#if defined(DF_ENTERPRISE)
725718
extern char *resolve_php_frame(uint32_t pid,
726719
uint64_t zend_function_ptr,
@@ -742,12 +735,6 @@ void rust_log_wrapper(LogLevel level,
742735
const char *file_path,
743736
int line_number);
744737

745-
/**
746-
* Read TPBASE offset from kernel functions
747-
* Returns the offset of fsbase/tpidr in task_struct, or -1 on failure
748-
*/
749-
int64_t read_tpbase_offset(void);
750-
751738
int rustc_demangle(const char *mangled, char *out, size_t out_size);
752739

753740
unwind_table_t *unwind_table_create(int32_t process_shard_list_map_fd,

agent/crates/trace-utils/src/unwind/tpbase.rs

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,21 @@ fn extract_tpbase_offset_from_btf() -> Result<u64> {
386386

387387
#[cfg(target_arch = "aarch64")]
388388
{
389-
// For ARM64: task_struct.thread.uw.tp_value
390-
// Default offset for common kernel configurations
389+
// Try parsing /sys/kernel/btf/vmlinux for ARM64
390+
match parse_btf_for_tpbase() {
391+
Ok(offset) => {
392+
debug!(
393+
"Extracted TPBASE offset {} ({:#x}) from BTF",
394+
offset, offset
395+
);
396+
return Ok(offset);
397+
}
398+
Err(e) => {
399+
debug!("BTF parsing failed: {}", e);
400+
}
401+
}
402+
403+
// Fallback to hardcoded defaults based on common kernel configurations
391404
get_default_tpbase_offset()
392405
}
393406

@@ -400,7 +413,7 @@ fn extract_tpbase_offset_from_btf() -> Result<u64> {
400413
}
401414

402415
/// Parse BTF information from /sys/kernel/btf/vmlinux to get TPBASE offset
403-
#[cfg(target_arch = "x86_64")]
416+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
404417
fn parse_btf_for_tpbase() -> Result<u64> {
405418
use std::fs::File;
406419
use std::io::Read;
@@ -419,8 +432,11 @@ fn parse_btf_for_tpbase() -> Result<u64> {
419432
parse_btf_task_struct_fsbase(&btf_data)
420433
}
421434

422-
/// Parse BTF data to find task_struct.thread.fsbase offset
423-
#[cfg(target_arch = "x86_64")]
435+
/// Parse BTF task_struct to find fsbase/tp_value offset
436+
///
437+
/// On x86_64: finds task_struct.thread.fsbase
438+
/// On ARM64: finds task_struct.thread.uw.tp_value
439+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
424440
fn parse_btf_task_struct_fsbase(btf_data: &[u8]) -> Result<u64> {
425441
// BTF header structure (from include/uapi/linux/btf.h)
426442
// struct btf_header {
@@ -469,13 +485,34 @@ fn parse_btf_task_struct_fsbase(btf_data: &[u8]) -> Result<u64> {
469485
let task_struct_id = find_btf_struct_by_name(type_section, str_section, "task_struct")?;
470486

471487
// Find thread member in task_struct
472-
let thread_offset =
473-
find_btf_member_offset(type_section, str_section, task_struct_id, "thread")?;
488+
let thread_info = find_btf_member_info(type_section, str_section, task_struct_id, "thread")?;
489+
let thread_offset = thread_info.offset;
490+
let thread_type_id = thread_info.type_id;
491+
492+
// Architecture-specific: x86_64 uses fsbase, ARM64 uses uw.tp_value
493+
let fsbase_offset = {
494+
#[cfg(target_arch = "x86_64")]
495+
{
496+
find_btf_member_offset(type_section, str_section, thread_type_id, "fsbase")?
497+
}
474498

475-
// Find thread_struct type and fsbase offset within it
476-
let thread_type_id = find_btf_member_type(type_section, str_section, task_struct_id, "thread")?;
477-
let fsbase_offset =
478-
find_btf_member_offset(type_section, str_section, thread_type_id, "fsbase")?;
499+
#[cfg(target_arch = "aarch64")]
500+
{
501+
// ARM64: thread_struct.uw.tp_value
502+
let uw_info = find_btf_member_info(type_section, str_section, thread_type_id, "uw")?;
503+
let uw_offset = uw_info.offset;
504+
let uw_type_id = uw_info.type_id;
505+
let tp_value_offset =
506+
find_btf_member_offset(type_section, str_section, uw_type_id, "tp_value")?;
507+
uw_offset + tp_value_offset
508+
}
509+
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
510+
{
511+
return Err(Error::Msg(
512+
"TPBASE BTF parsing not supported for this architecture".to_string(),
513+
));
514+
}
515+
};
479516

480517
let total_offset = thread_offset + fsbase_offset;
481518

@@ -491,13 +528,13 @@ fn parse_btf_task_struct_fsbase(btf_data: &[u8]) -> Result<u64> {
491528
}
492529

493530
/// BTF type kinds
494-
#[cfg(target_arch = "x86_64")]
531+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
495532
const BTF_KIND_STRUCT: u32 = 4;
496-
#[cfg(target_arch = "x86_64")]
533+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
497534
const BTF_KIND_UNION: u32 = 5;
498535

499536
/// Calculate extra size for a BTF type based on its kind and vlen
500-
#[cfg(target_arch = "x86_64")]
537+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
501538
fn btf_type_extra_size(kind: u32, vlen: u32) -> usize {
502539
match kind {
503540
1 => 4, // BTF_KIND_INT
@@ -523,7 +560,7 @@ fn btf_type_extra_size(kind: u32, vlen: u32) -> usize {
523560
}
524561

525562
/// Find BTF struct type ID by name
526-
#[cfg(target_arch = "x86_64")]
563+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
527564
fn find_btf_struct_by_name(type_section: &[u8], str_section: &[u8], name: &str) -> Result<u32> {
528565
// BTF type format:
529566
// struct btf_type {
@@ -575,7 +612,7 @@ fn find_btf_struct_by_name(type_section: &[u8], str_section: &[u8], name: &str)
575612
}
576613

577614
/// BTF member info containing both offset and type ID
578-
#[cfg(target_arch = "x86_64")]
615+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
579616
struct BtfMemberInfo {
580617
/// Offset in bytes from the start of the struct
581618
offset: u64,
@@ -585,7 +622,7 @@ struct BtfMemberInfo {
585622

586623
/// Find both offset and type ID of a member in a BTF struct.
587624
/// This is the unified implementation that extracts all member info at once.
588-
#[cfg(target_arch = "x86_64")]
625+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
589626
fn find_btf_member_info(
590627
type_section: &[u8],
591628
str_section: &[u8],
@@ -659,7 +696,7 @@ fn find_btf_member_info(
659696
}
660697

661698
/// Find offset of a member in a BTF struct
662-
#[cfg(target_arch = "x86_64")]
699+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
663700
fn find_btf_member_offset(
664701
type_section: &[u8],
665702
str_section: &[u8],
@@ -669,19 +706,8 @@ fn find_btf_member_offset(
669706
find_btf_member_info(type_section, str_section, struct_id, member_name).map(|info| info.offset)
670707
}
671708

672-
/// Find type ID of a member in a BTF struct
673-
#[cfg(target_arch = "x86_64")]
674-
fn find_btf_member_type(
675-
type_section: &[u8],
676-
str_section: &[u8],
677-
struct_id: u32,
678-
member_name: &str,
679-
) -> Result<u32> {
680-
find_btf_member_info(type_section, str_section, struct_id, member_name).map(|info| info.type_id)
681-
}
682-
683709
/// Get null-terminated string from BTF string section
684-
#[cfg(target_arch = "x86_64")]
710+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
685711
fn get_btf_string(str_section: &[u8], offset: usize) -> &str {
686712
if offset >= str_section.len() {
687713
return "";

0 commit comments

Comments
 (0)