"""
Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
libkperf licensed under the Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
PURPOSE.
See the Mulan PSL v2 for more details.
Author: Victor Jin
Create: 2024-05-10
Description: ctype python Symbol module
"""
import ctypes
from typing import List, Any, Iterator
from .Config import UTF_8, sym_so
class CtypesSymbol(ctypes.Structure):
"""
struct Symbol {
unsigned long addr; // address (dynamic allocated) of this symbol
char* module; // binary name of which the symbol belongs to
char* symbolName; // name of the symbol with demangle
char* mangleName; // name of the symbol with no demangle
char* fileName; // corresponding file of current symbol
unsigned int lineNum; // line number of a symbol in the file
unsigned long offset;
unsigned long codeMapEndAddr; // function end address
unsigned long codeMapAddr; // real srcAddr of Asm Code or
char* mntPoint; // mount point
};
"""
_fields_ = [
('addr', ctypes.c_ulong),
('module', ctypes.c_char_p),
('symbolName', ctypes.c_char_p),
('mangleName', ctypes.c_char_p),
('fileName', ctypes.c_char_p),
('lineNum', ctypes.c_uint),
('offset', ctypes.c_ulong),
('codeMapEndAddr', ctypes.c_ulong),
('codeMapAddr', ctypes.c_ulong),
('firstLine', ctypes.c_uint),
('mntPoint', ctypes.c_char_p),
]
def __init__(self,
addr= 0,
module= '',
symbolName= '',
mangleName= '',
fileName= '',
lineNum= 0,
offset= 0,
codeMapEndAddr= 0,
codeMapAddr= 0,
firstLine=0,
mntPoint='',
*args, **kw):
super(CtypesSymbol, self).__init__(*args, **kw)
self.addr = ctypes.c_ulong(addr)
self.module = ctypes.c_char_p(module.encode(UTF_8))
self.symbolName = ctypes.c_char_p(symbolName.encode(UTF_8))
self.mangleName = ctypes.c_char_p(mangleName.encode(UTF_8))
self.fileName = ctypes.c_char_p(fileName.encode(UTF_8))
self.lineNum = ctypes.c_uint(lineNum)
self.offset = ctypes.c_ulong(offset)
self.codeMapEndAddr = ctypes.c_ulong(codeMapEndAddr)
self.codeMapAddr = ctypes.c_ulong(codeMapAddr)
self.firstLine = ctypes.c_uint(firstLine)
self.mntPoint = ctypes.c_char_p(mntPoint.encode(UTF_8))
class Symbol:
__slots__ = ['__c_sym','__module', '__symbolName', '__mangleName', '__fileName', '__mntPoint']
def __init__(self,
addr= 0,
module= '',
symbolName= '',
mangleName= '',
fileName= '',
lineNum= 0,
offset= 0,
codeMapEndAddr= 0,
codeMapAddr= 0,
firstLine=0,
mntPoint= ''):
self.__c_sym = CtypesSymbol(
addr=addr,
module=module,
symbolName=symbolName,
mangleName=mangleName,
fileName=fileName,
lineNum=lineNum,
offset=offset,
codeMapEndAddr=codeMapEndAddr,
codeMapAddr=codeMapAddr,
firstLine=firstLine,
mntPoint=mntPoint
)
@property
def c_sym(self):
return self.__c_sym
@property
def addr(self):
return self.c_sym.addr
@addr.setter
def addr(self, addr):
self.c_sym.addr = ctypes.c_ulong(addr)
@property
def module(self):
if not self.__module:
self.__module = self.c_sym.module.decode(UTF_8)
return self.__module
@module.setter
def module(self, module):
self.c_sym.module = ctypes.c_char_p(module.encode(UTF_8))
@property
def symbolName(self):
if not self.__symbolName:
self.__symbolName = self.c_sym.symbolName.decode(UTF_8)
return self.__symbolName
@symbolName.setter
def symbolName(self, symbolName):
self.c_sym.symbolName = ctypes.c_char_p(symbolName.encode(UTF_8))
@property
def mangleName(self):
if not self.__mangleName:
self.__mangleName = self.c_sym.mangleName.decode(UTF_8)
return self.__mangleName
@mangleName.setter
def mangleName(self, mangleName):
self.c_sym.mangleName = ctypes.c_char_p(mangleName.encode(UTF_8))
@property
def fileName(self):
if not self.__fileName:
self.__fileName = self.c_sym.fileName.decode(UTF_8)
return self.__fileName
@fileName.setter
def fileName(self, fileName):
self.c_sym.fileName = ctypes.c_char_p(fileName.encode(UTF_8))
@property
def mntPoint(self):
if not self.__mntPoint and self.c_sym.mntPoint:
self.__mntPoint = self.c_sym.mntPoint.decode(UTF_8)
return self.__mntPoint
@mntPoint.setter
def mntPoint(self, mntPoint):
self.c_sym.mntPoint = ctypes.c_char_p(mntPoint.encode(UTF_8))
@property
def lineNum(self):
return self.c_sym.lineNum
@lineNum.setter
def lineNum(self, lineNum):
self.c_sym.lineNum = ctypes.c_uint(lineNum)
@property
def offset(self):
return self.c_sym.offset
@offset.setter
def offset(self, offset):
self.c_sym.offset = ctypes.c_ulong(offset)
@property
def codeMapEndAddr(self):
return self.c_sym.codeMapEndAddr
@codeMapEndAddr.setter
def codeMapEndAddr(self, codeMapEndAddr):
self.c_sym.codeMapEndAddr = ctypes.c_ulong(codeMapEndAddr)
@property
def codeMapAddr(self):
return self.c_sym.codeMapAddr
@codeMapAddr.setter
def codeMapAddr(self, codeMapAddr):
self.c_sym.codeMapAddr = ctypes.c_ulong(codeMapAddr)
@property
def firstLine(self):
return self.c_sym.firstLine
@firstLine.setter
def firstLine(self, firstLine):
self.c_sym.firstLine = ctypes.c_uint(firstLine)
@classmethod
def from_c_sym(cls, c_sym):
symbol = cls()
symbol.__c_sym = c_sym
symbol.__module = None
symbol.__symbolName = None
symbol.__mangleName = None
symbol.__fileName = None
symbol.__mntPoint = None
return symbol
class CtypesStack(ctypes.Structure):
"""
struct Stack {
struct Symbol* symbol; // symbol info for current stack
struct Stack* next; // points to next position in stack
struct Stack* prev; // points to previous position in stack
} __attribute__((aligned(64)));
"""
pass
CtypesStack._fields_ = [
('symbol', ctypes.POINTER(CtypesSymbol)),
('next', ctypes.POINTER(CtypesStack)),
('prev', ctypes.POINTER(CtypesStack))
]
class Stack(object):
__slots__ = ['__c_stack', '__symbol', '__next', '__prev']
def __init__(self,
symbol= None,
next= None,
prev= None):
self.__c_stack = CtypesStack(
symbol=symbol.c_sym if symbol else None,
next=next.c_stack if next else None,
prev=prev.c_stack if prev else None)
@property
def c_stack(self):
return self.__c_stack
@property
def symbol(self):
if not self.__symbol:
self.__symbol = Symbol.from_c_sym(self.c_stack.symbol.contents) if self.c_stack.symbol else None
return self.__symbol
@symbol.setter
def symbol(self, symbol):
self.c_stack.symbol = symbol.c_sym if symbol else None
@property
def next(self):
if not self.__next:
self.__next = self.from_c_stack(self.c_stack.next.contents) if self.c_stack.next else None
return self.__next
@next.setter
def next(self, next):
self.c_stack.next = next.c_stack if next else None
@property
def prev(self):
if not self.__prev:
self.__prev = self.from_c_stack(self.c_stack.prev.contents) if self.c_stack.prev else None
return self.__prev
@prev.setter
def prev(self, prev):
self.c_stack.prev = prev.c_stack if prev else None
@classmethod
def from_c_stack(cls, c_stack):
stack = cls()
stack.__c_stack = c_stack
stack.__symbol = None
stack.__next = None
stack.__prev = None
return stack
class CtypesAsmCode(ctypes.Structure):
"""
struct AsmCode {
unsigned long addr; // address of asm file
char* code; // code of asm
char* fileName; // this source file name of this asm code
unsigned int lineNum; // the real line of this addr
};
"""
_fields_ = [
('addr', ctypes.c_ulong),
('code', ctypes.c_char_p),
('fileName', ctypes.c_char_p),
('lineNum', ctypes.c_uint)
]
def __init__(self,
addr= 0,
code= '',
fileName= '',
lineNum= 0,
*args, **kw):
super(CtypesAsmCode, self).__init__(*args, **kw)
self.addr = ctypes.c_ulong(addr)
self.code = ctypes.c_char_p(code.encode(UTF_8))
self.fileName = ctypes.c_char_p(fileName.encode(UTF_8))
self.lineNum = ctypes.c_uint(lineNum)
class AsmCode:
__slots__ = ['__c_asm_code']
def __init__(self,
addr= 0,
code= '',
fileName= '',
lineNum= 0):
self.__c_asm_code = CtypesAsmCode(
addr=addr,
code=code,
fileName=fileName,
lineNum=lineNum
)
@property
def c_asm_code(self):
return self.__c_asm_code
@property
def addr(self):
return self.c_asm_code.addr
@addr.setter
def addr(self, addr):
self.c_asm_code.addr = ctypes.c_ulong(addr)
@property
def code(self):
return self.c_asm_code.code.decode(UTF_8)
@code.setter
def code(self, code):
self.c_asm_code.code = ctypes.c_char_p(code.encode(UTF_8))
@property
def fileName(self):
return self.c_asm_code.fileName.decode(UTF_8)
@fileName.setter
def fileName(self, fileName):
self.c_asm_code.fileName = ctypes.c_char_p(fileName.encode(UTF_8))
@property
def lineNum(self):
return self.c_asm_code.lineNum
@lineNum.setter
def lineNum(self, lineNum):
self.c_asm_code.lineNum = ctypes.c_uint(lineNum)
@classmethod
def from_c_asm_code(cls, c_asm_code):
asm_code = cls()
asm_code.__c_asm_code = c_asm_code
return asm_code
class CtypesStackAsm(ctypes.Structure):
"""
struct StackAsm {
char* funcName; // function name of void
unsigned long funcStartAddr; // start address of function
unsigned long functFileOffset; // offset of function in this file
struct StackAsm* next; // points to next position in stack
struct AsmCode* asmCode; // asm code
};
"""
_fields_ = [
('fileName', ctypes.c_char_p),
('funcStartAddr', ctypes.c_ulong),
('functFileOffset', ctypes.c_ulong),
('next', ctypes.POINTER('CtypesStackAsm')),
('asmCode', ctypes.POINTER(CtypesAsmCode)),
]
def __init__(self,
fileName= '',
funcStartAddr= 0,
functFileOffset= 0,
next = None,
asmCode= None,
*args, **kw):
super(CtypesStackAsm, self).__init__(*args, **kw)
self.fileName = ctypes.c_char_p(fileName.encode(UTF_8))
self.funcStartAddr = ctypes.c_ulong(funcStartAddr)
self.functFileOffset = ctypes.c_ulong(functFileOffset)
self.next = next
self.asmCode = asmCode
class StackAsm:
__slots__ = ['__c_stack_asm']
def __init__(self,
fileName= '',
funcStartAddr= 0,
functFileOffset= 0,
next = None,
asmCode= None):
self.__c_stack_asm = CtypesStackAsm(
fileName=fileName,
funcStartAddr=funcStartAddr,
functFileOffset=functFileOffset,
next=next.c_stack_asm if next else None,
asmCode=asmCode.c_asm_code if asmCode else None,
)
@property
def c_stack_asm(self):
return self.__c_stack_asm
@property
def fileName(self):
return self.c_stack_asm.fileName.decode(UTF_8)
@fileName.setter
def fileName(self, fileName):
self.c_stack_asm.fileName = ctypes.c_char_p(fileName.encode(UTF_8))
@property
def funcStartAddr(self):
return self.c_stack_asm.funcStartAddr
@funcStartAddr.setter
def funcStartAddr(self, funcStartAddr):
self.c_stack_asm.funcStartAddr = ctypes.c_ulong(funcStartAddr)
@property
def functFileOffset(self):
return self.c_stack_asm.functFileOffset
@functFileOffset.setter
def functFileOffset(self, functFileOffset):
self.c_stack_asm.functFileOffset = ctypes.c_ulong(functFileOffset)
@property
def next(self):
return self.from_c_stack_asm(self.c_stack_asm.next.contents) if self.c_stack_asm.next else None
@next.setter
def next(self, next):
self.c_stack_asm.next = next.c_stack_asm if next else None
@property
def asmCode(self):
return AsmCode.from_c_asm_code(self.c_stack_asm.asmCode.contents) if self.c_stack_asm.asmCode else None
@asmCode.setter
def asmCode(self, asmCode):
self.c_stack_asm.asmCode = asmCode.c_asm_code if asmCode else None
@classmethod
def from_c_stack_asm(cls, c_stack_asm):
stack_asm = cls()
stack_asm.__c_stack_asm = c_stack_asm
return stack_asm
def SymResolverRecordKernel():
"""
int SymResolverRecordKernel();
"""
c_SymResolverRecordKernel = sym_so.SymResolverRecordKernel
c_SymResolverRecordKernel.argtypes = []
c_SymResolverRecordKernel.restype = ctypes.c_int
c_SymResolverRecordKernel()
def SymResolverRecordModule(pid):
"""
int SymResolverRecordModule(int pid);
"""
c_SymResolverRecordModule = sym_so.SymResolverRecordModule
c_SymResolverRecordModule.argtypes = [ctypes.c_int]
c_SymResolverRecordModule.restype = ctypes.c_int
c_pid = ctypes.c_int(pid)
c_SymResolverRecordModule(c_pid)
def SymResolverRecordModuleNoDwarf(pid):
"""
int SymResolverRecordModuleNoDwarf(int pid);
"""
c_SymResolverRecordModuleNoDwarf = sym_so.SymResolverRecordModuleNoDwarf
c_SymResolverRecordModuleNoDwarf.argtypes = [ctypes.c_int]
c_SymResolverRecordModuleNoDwarf.restype = ctypes.c_int
c_pid = ctypes.c_int(pid)
c_SymResolverRecordModuleNoDwarf(c_pid)
def StackToHash(pid, stackList):
"""
struct Stack* StackToHash(int pid, unsigned long* stack, int nr);
"""
c_StackToHash = sym_so.StackToHash
c_StackToHash.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_ulong), ctypes.c_int]
c_StackToHash.restype = ctypes.POINTER(CtypesStack)
stack_len = len(stackList)
c_pid = ctypes.c_int(pid)
c_stack_list = (ctypes.c_ulong * stack_len)(*stackList)
c_nr = ctypes.c_int(stack_len)
c_stack = c_StackToHash(c_pid, c_stack_list, c_nr)
if not c_stack:
return None
return Stack.from_c_stack(c_stack.contents)
def SymResolverMapAddr(pid, addr):
"""
struct Symbol* SymResolverMapAddr(int pid, unsigned long addr);
"""
c_SymResolverMapAddr = sym_so.SymResolverMapAddr
c_SymResolverMapAddr.argtypes = [ctypes.c_int, ctypes.c_ulong]
c_SymResolverMapAddr.restype = ctypes.POINTER(CtypesSymbol)
c_pid = ctypes.c_int(pid)
c_addr = ctypes.c_ulong(addr)
c_sym = c_SymResolverMapAddr(c_pid, c_addr)
if not c_sym:
return None
return Symbol.from_c_sym(c_sym.contents)
def FreeModuleData(pid):
"""
void FreeModuleData(int pid);
"""
c_FreeModuleData = sym_so.FreeModuleData
c_FreeModuleData.argtypes = [ctypes.c_int]
c_FreeModuleData.restype = None
c_pid = ctypes.c_int(pid)
c_FreeModuleData(c_pid)
def SymResolverDestroy():
"""
void SymResolverDestroy();
"""
c_SymResolverDestroy = sym_so.SymResolverDestroy
c_SymResolverDestroy.argtypes = []
c_SymResolverDestroy.restype = None
c_SymResolverDestroy()
__all__ = [
'CtypesSymbol',
'Symbol',
'CtypesStack',
'Stack',
'CtypesAsmCode',
'AsmCode',
'CtypesStackAsm',
'StackAsm',
'SymResolverRecordKernel',
'SymResolverRecordModule',
'SymResolverRecordModuleNoDwarf',
'StackToHash',
'SymResolverMapAddr',
'FreeModuleData',
'SymResolverDestroy',
]