library: exploit linux-4.5 resident memory enhancement

Since support already exists in the newlib branch this
represents an equivalent master branch implementation,
and this commit message is shared with 2 more patches.

Beginning with linux-4.5, the following new fields are
being added under that /proc/<pid>/status pseudo file:
 . RssAnon - size of resident anonymous memory
 . RssFile - size of resident file mappings
 . RssShmem - size of resident shared memory

p.s. Locked resident memory support was also added but
isn't directly related to the kernel 4.5 enhancements.

p.p.s. Archlinux, Debian-stretch and Fedora-23 already
are currently using a 4.5 linux kernel (as of 6/2/16).

Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2016-04-13 00:00:00 -05:00 committed by Craig Small
parent 7bf9457f71
commit cb0e210930
2 changed files with 83 additions and 69 deletions

View File

@ -113,7 +113,7 @@ static inline void free_acquired (proc_t *p, int reuse) {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
typedef struct status_table_struct { typedef struct status_table_struct {
unsigned char name[7]; // /proc/*/status field name unsigned char name[8]; // /proc/*/status field name
unsigned char len; // name length unsigned char len; // name length
#ifdef LABEL_OFFSET #ifdef LABEL_OFFSET
long offset; // jump address offset long offset; // jump address offset
@ -129,8 +129,11 @@ typedef struct status_table_struct {
#endif #endif
#define NUL {"", 0, 0}, #define NUL {"", 0, 0},
#define GPERF_TABLE_SIZE 128
// Derived from: // Derived from:
// gperf -7 --language=ANSI-C --key-positions=1,3,4 -C -n -c <if-not-piped> // gperf -7 --language=ANSI-C --key-positions=1,3,4 -C -n -c <if-not-piped>
// ( --key-positions verified by omission & reported "Computed positions" )
// //
// Suggested method: // Suggested method:
// Grep this file for "case_", then strip those down to the name. // Grep this file for "case_", then strip those down to the name.
@ -144,8 +147,8 @@ typedef struct status_table_struct {
// the F macro and replacing empty strings with the NUL define. // the F macro and replacing empty strings with the NUL define.
// //
// In the status_table_struct watch out for name size (grrr, expanding) // In the status_table_struct watch out for name size (grrr, expanding)
// and the number of entries (we mask with 63 for now). The table // and the number of entries. Currently, the table is padded to 128
// must be padded out to 64 entries, maybe 128 in the future. // entries and we therefore mask with 127.
static void status2proc(char *S, proc_t *restrict P, int is_proc){ static void status2proc(char *S, proc_t *restrict P, int is_proc){
long Threads = 0; long Threads = 0;
@ -155,78 +158,76 @@ static void status2proc(char *S, proc_t *restrict P, int is_proc){
// 128 entries because we trust the kernel to use ASCII names // 128 entries because we trust the kernel to use ASCII names
static const unsigned char asso[] = static const unsigned char asso[] =
{ {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
64, 64, 64, 64, 64, 64, 64, 64, 28, 64, 101, 101, 101, 101, 101, 101, 101, 101, 6, 101,
64, 64, 64, 64, 64, 64, 8, 25, 23, 25, 101, 101, 101, 101, 101, 45, 55, 25, 31, 50,
6, 25, 0, 3, 64, 64, 3, 64, 25, 64, 50, 10, 0, 35, 101, 101, 21, 101, 30, 101,
20, 1, 1, 5, 0, 30, 0, 0, 64, 64, 20, 36, 0, 5, 0, 40, 0, 0, 101, 101,
64, 64, 64, 64, 64, 64, 64, 3, 64, 0, 101, 101, 101, 101, 101, 101, 101, 30, 101, 15,
0, 18, 64, 10, 64, 10, 64, 64, 64, 20, 0, 1, 101, 10, 101, 10, 101, 101, 101, 25,
64, 20, 0, 64, 25, 64, 3, 15, 64, 0, 101, 40, 0, 101, 0, 50, 6, 40, 101, 1,
30, 64, 64, 64, 64, 64, 64, 64 35, 101, 101, 101, 101, 101, 101, 101
}; };
static const status_table_struct table[] = { static const status_table_struct table[GPERF_TABLE_SIZE] = {
F(VmHWM) F(VmHWM)
NUL NUL
F(VmLck)
NUL
F(VmSwap)
F(VmRSS)
NUL
F(VmStk)
NUL
F(Tgid)
F(State)
NUL
F(VmLib)
NUL
F(VmSize)
F(SigQ)
NUL
F(SigIgn)
NUL
F(VmPTE)
F(FDSize)
NUL
F(SigBlk)
NUL
F(ShdPnd)
F(VmData)
NUL
F(CapInh)
NUL
F(PPid)
NUL NUL
F(CapBnd)
NUL
F(SigPnd)
NUL NUL
F(VmPeak)
NUL
F(SigCgt)
NUL NUL
F(Threads) F(Threads)
NUL NUL NUL NUL
F(CapPrm) F(VmRSS)
NUL NUL F(VmSwap)
F(Pid) NUL NUL NUL
NUL F(Tgid)
F(CapEff) F(VmStk)
NUL NUL NUL NUL NUL
F(VmSize)
F(Gid) F(Gid)
NUL NUL NUL NUL
F(VmExe) F(VmPTE)
NUL NUL F(VmPeak)
NUL NUL NUL
F(ShdPnd)
F(Pid)
NUL NUL NUL
F(PPid)
F(VmLib)
NUL NUL NUL
F(SigPnd)
F(VmLck)
NUL NUL NUL
F(SigCgt)
F(State)
NUL NUL NUL
F(CapPrm)
F(Uid) F(Uid)
NUL NUL NUL NUL
F(Groups) F(SigIgn)
NUL NUL F(SigQ)
NUL NUL NUL
F(RssShmem)
F(Name) F(Name)
NUL NUL NUL
F(CapInh)
F(VmData)
NUL NUL NUL
F(FDSize)
NUL NUL NUL NUL
F(SigBlk)
NUL NUL NUL NUL
F(CapEff)
NUL NUL NUL NUL
F(CapBnd)
NUL NUL NUL NUL
F(VmExe)
NUL NUL NUL NUL
F(Groups)
NUL NUL NUL NUL
F(RssAnon)
NUL NUL NUL NUL
F(RssFile)
}; };
#undef F #undef F
@ -248,7 +249,7 @@ ENTER(0x220);
// examine a field name (hash and compare) // examine a field name (hash and compare)
base: base:
if(unlikely(!*S)) break; if(unlikely(!*S)) break;
entry = table[63 & (asso[(int)S[3]] + asso[(int)S[2]] + asso[(int)S[0]])]; entry = table[(GPERF_TABLE_SIZE -1) & (asso[(int)S[3]] + asso[(int)S[2]] + asso[(int)S[0]])];
colon = strchr(S, ':'); colon = strchr(S, ':');
if(unlikely(!colon)) break; if(unlikely(!colon)) break;
if(unlikely(colon[1]!='\t')) break; if(unlikely(colon[1]!='\t')) break;
@ -361,6 +362,15 @@ ENTER(0x220);
case_VmRSS: case_VmRSS:
P->vm_rss = strtol(S,&S,10); P->vm_rss = strtol(S,&S,10);
continue; continue;
case_RssAnon: // subset of VmRSS, linux-4.5
P->vm_rss_anon = strtol(S,&S,10);
continue;
case_RssFile: // subset of VmRSS, linux-4.5
P->vm_rss_file = strtol(S,&S,10);
continue;
case_RssShmem: // subset of VmRSS, linux-4.5
P->vm_rss_shared = strtol(S,&S,10);
continue;
case_VmSize: case_VmSize:
P->vm_size = strtol(S,&S,10); P->vm_size = strtol(S,&S,10);
continue; continue;
@ -436,6 +446,7 @@ ENTER(0x220);
LEAVE(0x220); LEAVE(0x220);
} }
#undef GPERF_TABLE_SIZE
static void supgrps_from_supgids (proc_t *p) { static void supgrps_from_supgids (proc_t *p) {
char *g, *s; char *g, *s;

View File

@ -116,6 +116,9 @@ typedef struct proc_t {
vm_size, // status equals 'size' (as kb) vm_size, // status equals 'size' (as kb)
vm_lock, // status locked pages (as kb) vm_lock, // status locked pages (as kb)
vm_rss, // status equals 'rss' and/or 'resident' (as kb) vm_rss, // status equals 'rss' and/or 'resident' (as kb)
vm_rss_anon, // status the 'anonymous' portion of vm_rss (as kb)
vm_rss_file, // status the 'file-backed' portion of vm_rss (as kb)
vm_rss_shared, // status the 'shared' portion of vm_rss (as kb)
vm_data, // status data only size (as kb) vm_data, // status data only size (as kb)
vm_stack, // status stack only size (as kb) vm_stack, // status stack only size (as kb)
vm_swap, // status based on linux-2.6.34 "swap ents" (as kb) vm_swap, // status based on linux-2.6.34 "swap ents" (as kb)