1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
/* ISC license. */
#include <sys/types.h>
#include <sys/utsname.h>
#include <skalibs/uint64.h>
#include <skalibs/bytestr.h>
#include <skalibs/stralloc.h>
#include <skalibs/genalloc.h>
#include <skalibs/djbunix.h>
#include "s6-ps.h"
static stralloc sysmap = STRALLOC_ZERO ;
static genalloc ind = GENALLOC_ZERO ;
int s6ps_wchan_init (char const *file)
{
if (file)
{
if (!openslurpclose(&sysmap, file)) return 0 ;
}
else
{
char *files[3] = { "/proc/kallsyms", 0, "/boot/System.map" } ;
struct utsname uts ;
size_t n ;
if (uname(&uts) < 0) return 0 ;
n = str_len(uts.release) ;
{
char buf[18 + n] ;
register unsigned int i = 0 ;
byte_copy(buf, 16, "/boot/System.map") ;
buf[16] = '-' ;
byte_copy(buf + 17, n + 1, uts.release) ;
files[1] = buf ;
for (; i < 3 ; i++)
if (openslurpclose(&sysmap, files[i])) break ;
if (i >= 3) return 0 ;
}
}
{
size_t i = 0 ;
if (!genalloc_append(size_t, &ind, &i)) goto err2 ;
for (i = 1 ; i <= sysmap.len ; i++)
if (sysmap.s[i-1] == '\n')
if (!genalloc_append(size_t, &ind, &i)) goto err ;
}
return 1 ;
err:
genalloc_free(size_t, &ind) ;
err2:
stralloc_free(&sysmap) ;
return 0 ;
}
void s6ps_wchan_finish (void)
{
genalloc_free(size_t, &ind) ;
stralloc_free(&sysmap) ;
}
static inline size_t lookup (uint64 addr, size_t *i)
{
size_t low = 0, mid, high = genalloc_len(size_t, &ind), len ;
for (;;)
{
uint64 cur ;
mid = (low + high) >> 1 ;
len = uint64_xscan(sysmap.s + genalloc_s(unsigned int, &ind)[mid], &cur) ;
if (!len) return 0 ;
if (cur == addr) break ;
if (mid == low) return 0 ;
if (addr < cur) high = mid ; else low = mid ;
}
*i = mid ;
return len ;
}
int s6ps_wchan_lookup (stralloc *sa, uint64 addr)
{
if (addr == (sizeof(void *) == 8 ? 0xffffffffffffffffULL : 0xffffffffUL))
return stralloc_catb(sa, "*", 1) ;
if (!addr) return stralloc_catb(sa, "-", 1) ;
if (sysmap.len)
{
size_t i ;
size_t len = lookup(addr, &i) ;
register size_t pos ;
if (!len) return stralloc_catb(sa, "?", 1) ;
pos = genalloc_s(size_t, &ind)[i] + len + 3 ;
return stralloc_catb(sa, sysmap.s + pos, genalloc_s(size_t, &ind)[i+1] - 1 - pos) ;
}
if (!stralloc_readyplus(sa, UINT64_FMT + 3)) return 0 ;
stralloc_catb(sa, "(0x", 3) ;
sa->len += uint64_fmt(sa->s + sa->len, addr) ;
stralloc_catb(sa, ")", 1) ;
return 1 ;
}
|