Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/AnonR/smanonr..../lib/0xtools
File: psnproc.py
# psn -- Linux Process Snapper by Tanel Poder [https://0x.tools]
[0] Fix | Delete
# Copyright 2019-2021 Tanel Poder
[1] Fix | Delete
#
[2] Fix | Delete
# This program is free software; you can redistribute it and/or modify
[3] Fix | Delete
# it under the terms of the GNU General Public License as published by
[4] Fix | Delete
# the Free Software Foundation; either version 2 of the License, or
[5] Fix | Delete
# (at your option) any later version.
[6] Fix | Delete
#
[7] Fix | Delete
# This program is distributed in the hope that it will be useful,
[8] Fix | Delete
# but WITHOUT ANY WARRANTY; without even the implied warranty of
[9] Fix | Delete
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
[10] Fix | Delete
# GNU General Public License for more details.
[11] Fix | Delete
#
[12] Fix | Delete
# You should have received a copy of the GNU General Public License along
[13] Fix | Delete
# with this program; if not, write to the Free Software Foundation, Inc.,
[14] Fix | Delete
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
[15] Fix | Delete
#
[16] Fix | Delete
# SPDX-License-Identifier: GPL-2.0-or-later
[17] Fix | Delete
[18] Fix | Delete
# structures defining /proc
[19] Fix | Delete
import os, os.path
[20] Fix | Delete
import re
[21] Fix | Delete
import platform
[22] Fix | Delete
[23] Fix | Delete
system_timer_hz = os.sysconf('SC_CLK_TCK')
[24] Fix | Delete
[25] Fix | Delete
class ProcSource:
[26] Fix | Delete
def __init__(self, name, path, available_columns, stored_column_names, task_level=False, read_samples=lambda f: [f.read()], parse_sample=lambda self, sample: sample.split()):
[27] Fix | Delete
self.name = name
[28] Fix | Delete
self.path = path
[29] Fix | Delete
self.available_columns = available_columns
[30] Fix | Delete
self.task_level = task_level
[31] Fix | Delete
self.read_samples = read_samples
[32] Fix | Delete
self.parse_sample = parse_sample
[33] Fix | Delete
[34] Fix | Delete
self.set_stored_columns(stored_column_names)
[35] Fix | Delete
[36] Fix | Delete
[37] Fix | Delete
[38] Fix | Delete
def set_stored_columns(self, stored_column_names):
[39] Fix | Delete
col_name_i, schema_type_i, source_i, transform_i = range(4)
[40] Fix | Delete
self.stored_column_names = stored_column_names or [c[0] for c in self.available_columns]
[41] Fix | Delete
[42] Fix | Delete
# find schema columns
[43] Fix | Delete
sample_cols = [('event_time', str), ('pid', int), ('task', int)]
[44] Fix | Delete
source_cols = [c for c in self.available_columns if c[col_name_i] in self.stored_column_names and c[col_name_i] not in dict(sample_cols) and c[1] is not None]
[45] Fix | Delete
self.schema_columns = sample_cols + source_cols
[46] Fix | Delete
[47] Fix | Delete
column_indexes = dict([(c[col_name_i], c[source_i]) for c in self.available_columns])
[48] Fix | Delete
[49] Fix | Delete
schema_extract_idx = [column_indexes[c[col_name_i]] for c in source_cols]
[50] Fix | Delete
schema_extract_convert = [c[schema_type_i] if len(c) == 3 else c[transform_i] for c in source_cols]
[51] Fix | Delete
self.schema_extract = list(zip(schema_extract_idx, schema_extract_convert))
[52] Fix | Delete
[53] Fix | Delete
self.insert_sql = "INSERT INTO '%s' VALUES (%s)" % (self.name, ','.join(['?' for i in self.schema_columns]))
[54] Fix | Delete
[55] Fix | Delete
[56] Fix | Delete
def sample(self, event_time, pid, task):
[57] Fix | Delete
sample_path = self.path % (pid, task) if self.task_level else self.path % pid
[58] Fix | Delete
[59] Fix | Delete
with open(sample_path) as f:
[60] Fix | Delete
full_sample = None
[61] Fix | Delete
raw_samples = self.read_samples(f)
[62] Fix | Delete
[63] Fix | Delete
def create_row_sample(raw_sample):
[64] Fix | Delete
full_sample = self.parse_sample(self, raw_sample)
[65] Fix | Delete
[66] Fix | Delete
# some syscall-specific code pushed down to general sampling function
[67] Fix | Delete
# call readlink() to get the file name for system calls that have a file descriptor as arg0
[68] Fix | Delete
filename = ''
[69] Fix | Delete
if self.name == 'syscall':
[70] Fix | Delete
# special case: kernel threads show all-zero "syscall" on newer kernels like 4.x
[71] Fix | Delete
# otherwise it incorrectly looks like that kernel is in a "read" syscall (id=0 on x86_64)
[72] Fix | Delete
if full_sample[0] == '-1' or full_sample == ['0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0']:
[73] Fix | Delete
full_sample = ['kernel_thread', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0']
[74] Fix | Delete
[75] Fix | Delete
try:
[76] Fix | Delete
syscall_id = full_sample[0] # get string version of syscall number or "running" or "-1"
[77] Fix | Delete
except (ValueError, IndexError) as e:
[78] Fix | Delete
print('problem extracting syscall id', self.name, 'sample:')
[79] Fix | Delete
printr(full_sample)
[80] Fix | Delete
print
[81] Fix | Delete
raise
[82] Fix | Delete
[83] Fix | Delete
if syscall_id in syscalls_with_fd_arg:
[84] Fix | Delete
try:
[85] Fix | Delete
arg0 = int(full_sample[1], 16)
[86] Fix | Delete
# a hacky way for avoiding reading false file descriptors for kernel threads on older kernels
[87] Fix | Delete
# (like 2.6.32) that show "syscall 0x0" for kernel threads + some random false arguments.
[88] Fix | Delete
# TODO refactor this and kernel_thread translation above
[89] Fix | Delete
if arg0 <= 65536:
[90] Fix | Delete
filename = os.readlink("/proc/%s/fd/%s" % (pid, arg0)) + " " + special_fds.get(arg0, '')
[91] Fix | Delete
else:
[92] Fix | Delete
filename = 'fd over 65536'
[93] Fix | Delete
[94] Fix | Delete
except (OSError) as e:
[95] Fix | Delete
# file has been closed or process has disappeared
[96] Fix | Delete
#print 'problem with translating fd to name /proc/%s/fd/%s' % (pid, arg0), 'sample:'
[97] Fix | Delete
#print full_sample
[98] Fix | Delete
#print
[99] Fix | Delete
filename = '-'
[100] Fix | Delete
[101] Fix | Delete
full_sample += (filename,)
[102] Fix | Delete
[103] Fix | Delete
r = [event_time, pid, task] + [convert(full_sample[idx]) for idx, convert in self.schema_extract]
[104] Fix | Delete
return r
[105] Fix | Delete
[106] Fix | Delete
try:
[107] Fix | Delete
return [create_row_sample(rs) for rs in raw_samples]
[108] Fix | Delete
except (ValueError, IndexError) as e:
[109] Fix | Delete
print('problem parsing', self.name, 'sample:')
[110] Fix | Delete
print(raw_samples)
[111] Fix | Delete
print
[112] Fix | Delete
raise
[113] Fix | Delete
[114] Fix | Delete
[115] Fix | Delete
### stat ###
[116] Fix | Delete
# process_state_name = {
[117] Fix | Delete
# 'R': 'Running (ON CPU)',
[118] Fix | Delete
# 'S': 'Sleeping (Interruptible)',
[119] Fix | Delete
# 'D': 'Disk (Uninterruptible)',
[120] Fix | Delete
# 'Z': 'Zombie',
[121] Fix | Delete
# 'T': 'Traced/Stopped',
[122] Fix | Delete
# 'W': 'Paging'
[123] Fix | Delete
# }
[124] Fix | Delete
[125] Fix | Delete
# https://github.com/torvalds/linux/blob/master/fs/proc/array.c
[126] Fix | Delete
# State W (paging) is not used in kernels 2.6.x onwards
[127] Fix | Delete
process_state_name = {
[128] Fix | Delete
'R': 'Running (ON CPU)', #/* 0x00 */
[129] Fix | Delete
'S': 'Sleep (Interruptible)', #/* 0x01 */
[130] Fix | Delete
'D': 'Disk (Uninterruptible)', #/* 0x02 */
[131] Fix | Delete
'T': '(stopped)', #/* 0x04 */
[132] Fix | Delete
't': '(tracing stop)', #/* 0x08 */
[133] Fix | Delete
'X': '(dead)', #/* 0x10 */
[134] Fix | Delete
'Z': '(zombie)', #/* 0x20 */
[135] Fix | Delete
'P': '(parked)', #/* 0x40 */
[136] Fix | Delete
#/* states beyond TASK_REPORT: */
[137] Fix | Delete
'I': '(idle)', #/* 0x80 */
[138] Fix | Delete
}
[139] Fix | Delete
[140] Fix | Delete
def parse_stat_sample(proc_source, sample):
[141] Fix | Delete
tokens = raw_tokens = sample.split()
[142] Fix | Delete
[143] Fix | Delete
# stitch together comm field of the form (word word)
[144] Fix | Delete
if raw_tokens[1][0] == '(' and raw_tokens[1][-1] != ')':
[145] Fix | Delete
tokens = raw_tokens[:2]
[146] Fix | Delete
raw_tokens = raw_tokens[2:]
[147] Fix | Delete
while tokens[-1][-1] != ')':
[148] Fix | Delete
tokens[-1] += ' ' + raw_tokens.pop(0)
[149] Fix | Delete
tokens.extend(raw_tokens)
[150] Fix | Delete
[151] Fix | Delete
return tokens
[152] Fix | Delete
[153] Fix | Delete
[154] Fix | Delete
trim_comm = re.compile('\d+')
[155] Fix | Delete
[156] Fix | Delete
[157] Fix | Delete
stat = ProcSource('stat', '/proc/%s/task/%s/stat', [
[158] Fix | Delete
('pid', int, 0),
[159] Fix | Delete
('comm', str, 1, lambda c: re.sub(trim_comm, '*', c)),
[160] Fix | Delete
('comm2', str, 1),
[161] Fix | Delete
('state_id', str, 2),
[162] Fix | Delete
('state', str, 2, lambda state_id: process_state_name.get(state_id, state_id)),
[163] Fix | Delete
('ppid', int, 3),
[164] Fix | Delete
('pgrp', int, 4),
[165] Fix | Delete
('session', int, 5),
[166] Fix | Delete
('tty_nr', int, 6),
[167] Fix | Delete
('tpgid', int, 7),
[168] Fix | Delete
('flags', None, 8),
[169] Fix | Delete
('minflt', int, 9),
[170] Fix | Delete
('cminflt', int, 10),
[171] Fix | Delete
('majflt', int, 11),
[172] Fix | Delete
('cmajflt', int, 12),
[173] Fix | Delete
('utime', int, 13),
[174] Fix | Delete
('stime', int, 14),
[175] Fix | Delete
('cutime', int, 15),
[176] Fix | Delete
('cstime', int, 16),
[177] Fix | Delete
('utime_sec', int, 13, lambda v: int(v) / system_timer_hz),
[178] Fix | Delete
('stime_sec', int, 14, lambda v: int(v) / system_timer_hz),
[179] Fix | Delete
('cutime_sec', int, 15, lambda v: int(v) / system_timer_hz),
[180] Fix | Delete
('cstime_sec', int, 16, lambda v: int(v) / system_timer_hz),
[181] Fix | Delete
('priority', int, 17),
[182] Fix | Delete
('nice', int, 18),
[183] Fix | Delete
('num_threads', int, 19),
[184] Fix | Delete
('itrealvalue', None, 20),
[185] Fix | Delete
('starttime', int, 21),
[186] Fix | Delete
('vsize', int, 22),
[187] Fix | Delete
('rss', int, 23),
[188] Fix | Delete
('rsslim', str, 24),
[189] Fix | Delete
('startcode', None, 25),
[190] Fix | Delete
('endcode', None, 26),
[191] Fix | Delete
('startstack', None, 27),
[192] Fix | Delete
('kstkesp', None, 28),
[193] Fix | Delete
('kstkeip', None, 29),
[194] Fix | Delete
('signal', None, 30),
[195] Fix | Delete
('blocked', None, 31),
[196] Fix | Delete
('sigignore', None, 32),
[197] Fix | Delete
('sigcatch', None, 33),
[198] Fix | Delete
('wchan', None, 34),
[199] Fix | Delete
('nswap', None, 35),
[200] Fix | Delete
('cnswap', None, 36),
[201] Fix | Delete
('exit_signal', int, 37),
[202] Fix | Delete
('processor', int, 38),
[203] Fix | Delete
('rt_priority', int, 39),
[204] Fix | Delete
('policy', None, 40),
[205] Fix | Delete
('delayacct_blkio_ticks', int, 41),
[206] Fix | Delete
('guest_time', int, 42),
[207] Fix | Delete
('cgust_time', int, 43),
[208] Fix | Delete
('start_data', None, 44),
[209] Fix | Delete
('end_data', None, 45),
[210] Fix | Delete
('start_brk', None, 46),
[211] Fix | Delete
('arg_start', None, 47),
[212] Fix | Delete
('arg_end', None, 48),
[213] Fix | Delete
('env_start', None, 49),
[214] Fix | Delete
('env_end', None, 50),
[215] Fix | Delete
('exit_code', int, 51),
[216] Fix | Delete
], None,
[217] Fix | Delete
task_level=True,
[218] Fix | Delete
parse_sample=parse_stat_sample)
[219] Fix | Delete
[220] Fix | Delete
[221] Fix | Delete
[222] Fix | Delete
### status ###
[223] Fix | Delete
def parse_status_sample(proc_source, sample):
[224] Fix | Delete
lines = sample.split('\n')
[225] Fix | Delete
[226] Fix | Delete
sample_values = []
[227] Fix | Delete
[228] Fix | Delete
for line in [l for l in lines if l]:
[229] Fix | Delete
line_tokens = line.split()
[230] Fix | Delete
n, v = line_tokens[0][:-1].lower(), ' '.join(line_tokens[1:])
[231] Fix | Delete
n_kb = n + '_kb'
[232] Fix | Delete
[233] Fix | Delete
# missing values take default parse function value: assume no order change, and that available_columns contains all possible field names
[234] Fix | Delete
while len(sample_values) < len(proc_source.available_columns) and proc_source.available_columns[len(sample_values)][0] not in (n, n_kb):
[235] Fix | Delete
parse_fn = proc_source.available_columns[len(sample_values)][1]
[236] Fix | Delete
sample_values.append(parse_fn())
[237] Fix | Delete
[238] Fix | Delete
if len(sample_values) < len(proc_source.available_columns):
[239] Fix | Delete
sample_values.append(v)
[240] Fix | Delete
[241] Fix | Delete
return sample_values
[242] Fix | Delete
[243] Fix | Delete
[244] Fix | Delete
status = ProcSource('status', '/proc/%s/status', [
[245] Fix | Delete
('name', str, 0),
[246] Fix | Delete
('umask', str, 1),
[247] Fix | Delete
('state', str, 2), # remove duplicate with stat
[248] Fix | Delete
('tgid', int, 3),
[249] Fix | Delete
('ngid', int, 4),
[250] Fix | Delete
('pid', int, 5),
[251] Fix | Delete
('ppid', int, 6), # remove duplicate with stat
[252] Fix | Delete
('tracerpid', int, 7),
[253] Fix | Delete
('uid', int, 8, lambda v: int(v.split()[0])),
[254] Fix | Delete
('gid', int, 9, lambda v: int(v.split()[0])),
[255] Fix | Delete
('fdsize', int, 10),
[256] Fix | Delete
('groups', str, 11),
[257] Fix | Delete
('nstgid', str, 12),
[258] Fix | Delete
('nspid', str, 13),
[259] Fix | Delete
('nspgid', str, 14),
[260] Fix | Delete
('nssid', str, 15),
[261] Fix | Delete
('vmpeak_kb', int, 16, lambda v: int(v.split()[0])),
[262] Fix | Delete
('vmsize_kb', int, 17, lambda v: int(v.split()[0])),
[263] Fix | Delete
('vmlck_kb', int, 18, lambda v: int(v.split()[0])),
[264] Fix | Delete
('vmpin_kb', int, 19, lambda v: int(v.split()[0])),
[265] Fix | Delete
('vmhwm_kb', int, 20, lambda v: int(v.split()[0])),
[266] Fix | Delete
('vmrss_kb', int, 21, lambda v: int(v.split()[0])),
[267] Fix | Delete
('rssanon_kb', int, 22, lambda v: int(v.split()[0])),
[268] Fix | Delete
('rssfile_kb', int, 23, lambda v: int(v.split()[0])),
[269] Fix | Delete
('rssshmem_kb', int, 24, lambda v: int(v.split()[0])),
[270] Fix | Delete
('vmdata_kb', int, 25, lambda v: int(v.split()[0])),
[271] Fix | Delete
('vmstk_kb', int, 26, lambda v: int(v.split()[0])),
[272] Fix | Delete
('vmexe_kb', int, 27, lambda v: int(v.split()[0])),
[273] Fix | Delete
('vmlib_kb', int, 28, lambda v: int(v.split()[0])),
[274] Fix | Delete
('vmpte_kb', int, 29, lambda v: int(v.split()[0])),
[275] Fix | Delete
('vmpmd_kb', int, 30, lambda v: int(v.split()[0])),
[276] Fix | Delete
('vmswap_kb', int, 31, lambda v: int(v.split()[0])),
[277] Fix | Delete
('hugetlbpages_kb', int, 32, lambda v: int(v.split()[0])),
[278] Fix | Delete
('threads', int, 33),
[279] Fix | Delete
('sigq', str, 34),
[280] Fix | Delete
('sigpnd', str, 35),
[281] Fix | Delete
('shdpnd', str, 36),
[282] Fix | Delete
('sigblk', str, 37),
[283] Fix | Delete
('sigign', str, 38),
[284] Fix | Delete
('sigcgt', str, 39),
[285] Fix | Delete
('capinh', str, 40),
[286] Fix | Delete
('capprm', str, 41),
[287] Fix | Delete
('capeff', str, 42),
[288] Fix | Delete
('capbnd', str, 43),
[289] Fix | Delete
('capamb', str, 44),
[290] Fix | Delete
('seccomp', int, 45),
[291] Fix | Delete
('cpus_allowed', str, 46),
[292] Fix | Delete
('cpus_allowed_list', str, 47),
[293] Fix | Delete
('mems_allowed', str, 48),
[294] Fix | Delete
('mems_allowed_list', str, 49),
[295] Fix | Delete
('voluntary_ctxt_switches', int, 50),
[296] Fix | Delete
('nonvoluntary_ctxt_switches', int, 51)
[297] Fix | Delete
], None, task_level=False, parse_sample=parse_status_sample)
[298] Fix | Delete
[299] Fix | Delete
[300] Fix | Delete
### syscall ###
[301] Fix | Delete
def extract_system_call_ids(unistd_64_fh):
[302] Fix | Delete
syscall_id_to_name = {'running': '[running]', '-1': '[kernel_direct]', 'kernel_thread':'[kernel_thread]'}
[303] Fix | Delete
[304] Fix | Delete
# examples from a unistd.h file
[305] Fix | Delete
# #define __NR_mount 40
[306] Fix | Delete
# #define __NR3264_truncate 45
[307] Fix | Delete
[308] Fix | Delete
for name_prefix in ['__NR_', '__NR3264_']:
[309] Fix | Delete
for line in unistd_64_fh.readlines():
[310] Fix | Delete
tokens = line.split()
[311] Fix | Delete
if tokens and len(tokens) == 3 and tokens[0] == '#define':
[312] Fix | Delete
_, s_name, s_id = tokens
[313] Fix | Delete
if s_name.startswith(name_prefix):
[314] Fix | Delete
s_name = s_name[len(name_prefix):]
[315] Fix | Delete
syscall_id_to_name[s_id] = s_name
[316] Fix | Delete
[317] Fix | Delete
return syscall_id_to_name
[318] Fix | Delete
[319] Fix | Delete
# currently assuming all platforms are x86_64
[320] Fix | Delete
def get_system_call_names():
[321] Fix | Delete
psn_dir=os.path.dirname(os.path.realpath(__file__))
[322] Fix | Delete
kernel_ver=platform.release().split('-')[0]
[323] Fix | Delete
[324] Fix | Delete
# this probably needds to be improved for better platform support
[325] Fix | Delete
if platform.machine() == 'aarch64':
[326] Fix | Delete
unistd_64_paths = ['/usr/include/asm-generic/unistd.h']
[327] Fix | Delete
else:
[328] Fix | Delete
unistd_64_paths = ['/usr/include/asm/unistd_64.h', '/usr/include/x86_64-linux-gnu/asm/unistd_64.h', '/usr/include/asm-x86_64/unistd.h', '/usr/include/asm/unistd.h', psn_dir+'/syscall_64_'+kernel_ver+'.h', psn_dir+'/syscall_64.h']
[329] Fix | Delete
[330] Fix | Delete
for path in unistd_64_paths:
[331] Fix | Delete
try:
[332] Fix | Delete
with open(path) as f:
[333] Fix | Delete
return extract_system_call_ids(f)
[334] Fix | Delete
except IOError as e:
[335] Fix | Delete
pass
[336] Fix | Delete
[337] Fix | Delete
raise Exception('unistd_64.h not found in' + ' or '.join(unistd_64_paths) + '.\n You may need to "yum install kernel-headers" or "apt-get install libc6-dev"\n until this dependency is removed in a newer pSnapper version')
[338] Fix | Delete
[339] Fix | Delete
[340] Fix | Delete
syscall_id_to_name = get_system_call_names()
[341] Fix | Delete
[342] Fix | Delete
# define syscalls for which we can look up filename from fd argument
[343] Fix | Delete
# before the change for Python 3
[344] Fix | Delete
#syscall_name_to_id = dict((y,x) for x,y in syscall_id_to_name.iteritems())
[345] Fix | Delete
syscall_name_to_id = dict((y,x) for x,y in syscall_id_to_name.items())
[346] Fix | Delete
[347] Fix | Delete
syscalls_with_fd_arg = set([
[348] Fix | Delete
syscall_name_to_id.get('read' , 'N/A')
[349] Fix | Delete
, syscall_name_to_id.get('write' , 'N/A')
[350] Fix | Delete
, syscall_name_to_id.get('pread64' , 'N/A')
[351] Fix | Delete
, syscall_name_to_id.get('pwrite64' , 'N/A')
[352] Fix | Delete
, syscall_name_to_id.get('fsync' , 'N/A')
[353] Fix | Delete
, syscall_name_to_id.get('fdatasync' , 'N/A')
[354] Fix | Delete
, syscall_name_to_id.get('recvfrom' , 'N/A')
[355] Fix | Delete
, syscall_name_to_id.get('sendto' , 'N/A')
[356] Fix | Delete
, syscall_name_to_id.get('recvmsg' , 'N/A')
[357] Fix | Delete
, syscall_name_to_id.get('sendmsg' , 'N/A')
[358] Fix | Delete
, syscall_name_to_id.get('epoll_wait' , 'N/A')
[359] Fix | Delete
, syscall_name_to_id.get('ioctl' , 'N/A')
[360] Fix | Delete
, syscall_name_to_id.get('accept' , 'N/A')
[361] Fix | Delete
, syscall_name_to_id.get('accept4' , 'N/A')
[362] Fix | Delete
, syscall_name_to_id.get('getdents' , 'N/A')
[363] Fix | Delete
, syscall_name_to_id.get('getdents64' , 'N/A')
[364] Fix | Delete
, syscall_name_to_id.get('unlinkat' , 'N/A')
[365] Fix | Delete
, syscall_name_to_id.get('fstat' , 'N/A')
[366] Fix | Delete
, syscall_name_to_id.get('fstatfs' , 'N/A')
[367] Fix | Delete
, syscall_name_to_id.get('newfstatat' , 'N/A')
[368] Fix | Delete
, syscall_name_to_id.get('openat' , 'N/A')
[369] Fix | Delete
, syscall_name_to_id.get('readv' , 'N/A')
[370] Fix | Delete
, syscall_name_to_id.get('writev' , 'N/A')
[371] Fix | Delete
, syscall_name_to_id.get('preadv' , 'N/A')
[372] Fix | Delete
, syscall_name_to_id.get('pwritev' , 'N/A')
[373] Fix | Delete
, syscall_name_to_id.get('preadv2' , 'N/A')
[374] Fix | Delete
, syscall_name_to_id.get('pwritev2' , 'N/A')
[375] Fix | Delete
])
[376] Fix | Delete
[377] Fix | Delete
special_fds = { 0:'(stdin) ', 1:'(stdout)', 2:'(stderr)' }
[378] Fix | Delete
[379] Fix | Delete
def parse_syscall_sample(proc_source, sample):
[380] Fix | Delete
tokens = sample.split()
[381] Fix | Delete
if tokens[0] == 'running':
[382] Fix | Delete
return (tokens[0], '', '', '', '', '', '', None, None)
[383] Fix | Delete
else:
[384] Fix | Delete
return tokens
[385] Fix | Delete
[386] Fix | Delete
[387] Fix | Delete
trim_socket = re.compile('\d+')
[388] Fix | Delete
[389] Fix | Delete
syscall = ProcSource('syscall', '/proc/%s/task/%s/syscall', [
[390] Fix | Delete
('syscall_id', int, 0, lambda sn: -2 if sn == 'running' else int(sn)),
[391] Fix | Delete
('syscall', str, 0, lambda sn: syscall_id_to_name[sn]), # convert syscall_id via unistd_64.h into call name
[392] Fix | Delete
('arg0', str, 1),
[393] Fix | Delete
('arg1', str, 2),
[394] Fix | Delete
('arg2', str, 3),
[395] Fix | Delete
('arg3', str, 4),
[396] Fix | Delete
('arg4', str, 5),
[397] Fix | Delete
('arg5', str, 6),
[398] Fix | Delete
('esp', None, 7), # stack pointer
[399] Fix | Delete
('eip', None, 8), # program counter/instruction pointer
[400] Fix | Delete
('filename', str, 9, lambda fn: re.sub(trim_socket, '*', fn) if fn.split(':')[0] in ['socket','pipe'] else fn),
[401] Fix | Delete
('filename2', str, 9),
[402] Fix | Delete
('filenamesum',str, 9, lambda fn: re.sub(trim_socket, '*', fn)),
[403] Fix | Delete
('basename', str, 9, lambda fn: re.sub(trim_socket, '*', fn) if fn.split(':')[0] in ['socket','pipe'] else os.path.basename(fn)), # filename if syscall has fd as arg0
[404] Fix | Delete
('dirname', str, 9, lambda fn: re.sub(trim_socket, '*', fn) if fn.split(':')[0] in ['socket','pipe'] else os.path.dirname(fn)), # filename if syscall has fd as arg0
[405] Fix | Delete
], None,
[406] Fix | Delete
task_level=True, parse_sample=parse_syscall_sample)
[407] Fix | Delete
[408] Fix | Delete
[409] Fix | Delete
### get file name from file descriptor ###
[410] Fix | Delete
#filename = ProcSource('fd', '/proc/%s/task/%s/fd', [('wchan', str, 0)], ['wchan'], task_level=True)
[411] Fix | Delete
[412] Fix | Delete
### process cmdline args ###
[413] Fix | Delete
def parse_cmdline_sample(proc_source,sample):
[414] Fix | Delete
# the cmdline entry may have spaces in it and happens to have a \000 in the end
[415] Fix | Delete
# the split [] hack is due to postgres having some extra spaces in its cmdlines
[416] Fix | Delete
return [sample.split('\000')[0].strip()]
[417] Fix | Delete
[418] Fix | Delete
cmdline = ProcSource('cmdline', '/proc/%s/task/%s/cmdline', [('cmdline', str, 0)], ['cmdline'], task_level=True, parse_sample=parse_cmdline_sample)
[419] Fix | Delete
[420] Fix | Delete
### wchan ###
[421] Fix | Delete
wchan = ProcSource('wchan', '/proc/%s/task/%s/wchan', [('wchan', str, 0)], ['wchan'], task_level=True)
[422] Fix | Delete
[423] Fix | Delete
[424] Fix | Delete
### io ###
[425] Fix | Delete
def parse_io_sample(proc_source, sample):
[426] Fix | Delete
return [line.split()[1] if line else '' for line in sample.split('\n')]
[427] Fix | Delete
[428] Fix | Delete
io = ProcSource('io', '/proc/%s/task/%s/io', [
[429] Fix | Delete
('rchar', int, 0),
[430] Fix | Delete
('wchar', int, 1),
[431] Fix | Delete
('syscr', int, 2),
[432] Fix | Delete
('syscw', int, 3),
[433] Fix | Delete
('read_bytes', int, 4),
[434] Fix | Delete
('write_bytes', int, 5),
[435] Fix | Delete
('cancelled_write_bytes', int, 6),
[436] Fix | Delete
], None,
[437] Fix | Delete
task_level=True,
[438] Fix | Delete
parse_sample=parse_io_sample)
[439] Fix | Delete
[440] Fix | Delete
[441] Fix | Delete
[442] Fix | Delete
### net/dev ### (not accounted at process level)
[443] Fix | Delete
def read_net_samples(fh):
[444] Fix | Delete
return fh.readlines()[2:]
[445] Fix | Delete
[446] Fix | Delete
[447] Fix | Delete
def parse_net_sample(proc_source, sample):
[448] Fix | Delete
fields = sample.split()
[449] Fix | Delete
fields[0] = fields[0][:-1]
[450] Fix | Delete
return fields
[451] Fix | Delete
[452] Fix | Delete
[453] Fix | Delete
net = ProcSource('net', '/proc/%s/task/%s/net/dev', [
[454] Fix | Delete
('iface', str, 0),
[455] Fix | Delete
('rx_bytes', str, 1),
[456] Fix | Delete
('rx_packets', str, 2),
[457] Fix | Delete
('rx_errs', str, 3),
[458] Fix | Delete
('rx_drop', str, 4),
[459] Fix | Delete
('rx_fifo', str, 5),
[460] Fix | Delete
('rx_frame', str, 6),
[461] Fix | Delete
('rx_compressed', str, 7),
[462] Fix | Delete
('rx_multicast', str, 8),
[463] Fix | Delete
('tx_bytes', str, 9),
[464] Fix | Delete
('tx_packets', str, 10),
[465] Fix | Delete
('tx_errs', str, 11),
[466] Fix | Delete
('tx_drop', str, 12),
[467] Fix | Delete
('tx_fifo', str, 13),
[468] Fix | Delete
('tx_colls', str, 14),
[469] Fix | Delete
('tx_carrier', str, 15),
[470] Fix | Delete
('tx_compressed', str, 16),
[471] Fix | Delete
], None,
[472] Fix | Delete
read_samples=read_net_samples,
[473] Fix | Delete
parse_sample=parse_net_sample)
[474] Fix | Delete
[475] Fix | Delete
[476] Fix | Delete
[477] Fix | Delete
### stack ###
[478] Fix | Delete
def read_stack_samples(fh):
[479] Fix | Delete
result = ''
[480] Fix | Delete
[481] Fix | Delete
# reverse stack and ignore the (reversed) top frame 0xfffffffffffff
[482] Fix | Delete
# | |
[483] Fix | Delete
# v v
[484] Fix | Delete
for x in fh.readlines()[::-1][1:]:
[485] Fix | Delete
func = x.split(' ')[1].split('+')[0]
[486] Fix | Delete
if func not in ['entry_SYSCALL_64_after_hwframe','do_syscall_64','el0t_64_sync_handler',
[487] Fix | Delete
'el0_svc', 'do_el0_svc', 'el0_svc_common.constprop.0', 'invoke_syscall.constprop.0' ]:
[488] Fix | Delete
if result: # skip writing the 1st "->"
[489] Fix | Delete
result += '->'
[490] Fix | Delete
result += func + '()'
[491] Fix | Delete
[492] Fix | Delete
return [result or '-']
[493] Fix | Delete
[494] Fix | Delete
[495] Fix | Delete
stack = ProcSource('stack', '/proc/%s/task/%s/stack', [
[496] Fix | Delete
('kstack', str, 0),
[497] Fix | Delete
], None,
[498] Fix | Delete
task_level=True,
[499] Fix | Delete
12
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function