1from core.cvalue import sizeof, value
2from memory import GetLedgerEntryWithName, Memstats
3from process import GetProcName, GetProcPID, GetTaskFromProc, GetTaskSummary
4from scheduler import GetRecentTimestamp
5from utils import Cast
6from xnu import header, kern, lldb_command, unsigned
7from xnudefines import JETSAM_PRIORITY_MAX, P_MEMSTAT_FROZEN
8
9
10# Macro: showmemorystatus
11def CalculateLedgerPeak(phys_footprint_entry):
12    """
13    Internal function to calculate ledger peak value for the given phys footprint entry
14    params: phys_footprint_entry - value representing struct ledger_entry *
15    return: value - representing the ledger peak for the given phys footprint entry
16    """
17    return max(phys_footprint_entry['balance'], phys_footprint_entry.get('interval_max', 0))
18
19def IsProcFrozen(proc):
20    if not proc:
21        return 'N'
22    return 'Y' if proc.p_memstat_state & P_MEMSTAT_FROZEN else 'N'
23
24@header(f'{"effective": >12s} {"requested": >12s} {"assertion": >12s}'
25        f'{"state": >12s} {"dirty": >12s}'
26        f'{"frozen": >8s} {"relaunch": >10s} '
27        f'{"physical": >14s} {"iokit": >10s} {"footprint": >12s} '
28        f'{"recent_peak": >12s} {"lifemax": >10s} {"limit": >10s} '
29        f'{"pid": >8s} {"name": <32s}\n'
30        f'{"": >8s} {"priority": >12s} {"priority": >12s} '
31        f'{"priority": >12s} {"": >12s} '
32        f'{"": >8s} {"": >10s} '
33        f'{"(pages)": >14s} {"(pages)": >10s} {"(pages)": >12s} '
34        f'{"(pages)": >12s} {"(pages)": >10s} {"(pages)": >10s}  {"": <32s}')
35def GetMemoryStatusNode(proc_val):
36    """
37    Internal function to get memorystatus information from the given proc
38    params: proc - value representing struct proc *
39    return: str - formatted output information for proc object
40    """
41    out_str = ''
42    task_val = GetTaskFromProc(proc_val)
43    if task_val is None:
44        return out_str
45
46    task_ledgerp = task_val.ledger
47    ledger_template = kern.globals.task_ledger_template
48
49    task_physmem_footprint_ledger_entry = GetLedgerEntryWithName(ledger_template, task_ledgerp, 'phys_mem')
50    task_iokit_footprint_ledger_entry = GetLedgerEntryWithName(ledger_template, task_ledgerp, 'iokit_mapped')
51    task_phys_footprint_ledger_entry = GetLedgerEntryWithName(ledger_template, task_ledgerp, 'phys_footprint')
52    page_size = kern.globals.page_size
53
54    phys_mem_footprint = task_physmem_footprint_ledger_entry['balance'] // page_size
55    iokit_footprint = task_iokit_footprint_ledger_entry['balance'] // page_size
56    phys_footprint = task_phys_footprint_ledger_entry['balance'] // page_size
57    phys_footprint_limit = task_phys_footprint_ledger_entry['limit'] // page_size
58    ledger_peak = CalculateLedgerPeak(task_phys_footprint_ledger_entry)
59    phys_footprint_spike = ledger_peak // page_size
60    phys_footprint_lifetime_max = task_phys_footprint_ledger_entry['lifetime_max'] // page_size
61
62    format_string = '{:>12d} {:>12d} {:>12d} {:#012x} {:#012x} {:>8s} {:>10d} {:>14d} {:>10d} {:>12d}'
63    out_str += format_string.format(
64            proc_val.p_memstat_effectivepriority,
65            proc_val.p_memstat_requestedpriority,
66            proc_val.p_memstat_assertionpriority,
67            proc_val.p_memstat_state,
68            proc_val.p_memstat_dirty,
69            IsProcFrozen(proc_val),
70            proc_val.p_memstat_relaunch_flags,
71            phys_mem_footprint,
72            iokit_footprint,
73            phys_footprint)
74    if phys_footprint != phys_footprint_spike:
75        out_str += ' {: >12d}'.format(phys_footprint_spike)
76    else:
77        out_str += ' {: >12s}'.format('-')
78    out_str += ' {: >10d} {: >10d} {:>8d} {: <32s}'.format(
79            phys_footprint_lifetime_max,
80            phys_footprint_limit,
81            GetProcPID(proc_val),
82            GetProcName(proc_val))
83    return out_str
84
85@lldb_command('showmemorystatus')
86def ShowMemoryStatus(cmd_args=None):
87    """
88    Routine to display each entry in jetsam list with a summary of pressure statistics
89    Usage: showmemorystatus
90    """
91    bucket_index = 0
92    print(GetMemoryStatusNode.header)
93    while bucket_index <= JETSAM_PRIORITY_MAX:
94        current_bucket = kern.globals.memstat_bucket[bucket_index]
95        current_list = current_bucket.list
96        current_proc = Cast(current_list.tqh_first, 'proc *')
97        while unsigned(current_proc) != 0:
98            print(GetMemoryStatusNode(current_proc))
99            current_proc = current_proc.p_memstat_list.tqe_next
100        bucket_index += 1
101
102# EndMacro: showmemorystatus
103