Merge ^/head r309519 through r309757.
This commit is contained in:
commit
1bde3b7066
@ -147,6 +147,9 @@ OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_
|
||||
OLD_DIRS+=usr/lib/clang/3.9.0/lib/freebsd
|
||||
OLD_DIRS+=usr/lib/clang/3.9.0/lib
|
||||
OLD_DIRS+=usr/lib/clang/3.9.0
|
||||
# 20161205: libproc version bump
|
||||
OLD_LIBS+=usr/lib/libproc.so.3
|
||||
OLD_LIBS+=usr/lib32/libproc.so.3
|
||||
# 20161127: Remove vm_page_cache(9)
|
||||
OLD_FILES+=usr/share/man/man9/vm_page_cache.9.gz
|
||||
# 20161124: new clang import which bumps version from 3.8.0 to 3.9.0.
|
||||
|
30
bin/dd/dd.c
30
bin/dd/dd.c
@ -47,11 +47,14 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/capsicum.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/filio.h>
|
||||
#include <sys/mtio.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <capsicum_helpers.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
@ -92,6 +95,10 @@ main(int argc __unused, char *argv[])
|
||||
jcl(argv);
|
||||
setup();
|
||||
|
||||
caph_cache_catpages();
|
||||
if (cap_enter() == -1 && errno != ENOSYS)
|
||||
err(1, "unable to enter capability mode");
|
||||
|
||||
(void)signal(SIGINFO, siginfo_handler);
|
||||
(void)signal(SIGINT, terminate);
|
||||
|
||||
@ -125,6 +132,8 @@ static void
|
||||
setup(void)
|
||||
{
|
||||
u_int cnt;
|
||||
cap_rights_t rights;
|
||||
unsigned long cmds[] = { FIODTYPE, MTIOCTOP };
|
||||
|
||||
if (in.name == NULL) {
|
||||
in.name = "stdin";
|
||||
@ -133,13 +142,20 @@ setup(void)
|
||||
in.fd = open(in.name, O_RDONLY, 0);
|
||||
if (in.fd == -1)
|
||||
err(1, "%s", in.name);
|
||||
if (caph_limit_stdin() == -1)
|
||||
err(1, "unable to limit capability rights");
|
||||
}
|
||||
|
||||
getfdtype(&in);
|
||||
|
||||
cap_rights_init(&rights, CAP_READ, CAP_SEEK);
|
||||
if (cap_rights_limit(in.fd, &rights) == -1 && errno != ENOSYS)
|
||||
err(1, "unable to limit capability rights");
|
||||
|
||||
if (files_cnt > 1 && !(in.flags & ISTAPE))
|
||||
errx(1, "files is not supported for non-tape devices");
|
||||
|
||||
cap_rights_set(&rights, CAP_FTRUNCATE, CAP_IOCTL, CAP_WRITE);
|
||||
if (out.name == NULL) {
|
||||
/* No way to check for read access here. */
|
||||
out.fd = STDOUT_FILENO;
|
||||
@ -156,13 +172,27 @@ setup(void)
|
||||
if (out.fd == -1) {
|
||||
out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
|
||||
out.flags |= NOREAD;
|
||||
cap_rights_clear(&rights, CAP_READ);
|
||||
}
|
||||
if (out.fd == -1)
|
||||
err(1, "%s", out.name);
|
||||
if (caph_limit_stdout() == -1)
|
||||
err(1, "unable to limit capability rights");
|
||||
}
|
||||
|
||||
getfdtype(&out);
|
||||
|
||||
if (cap_rights_limit(out.fd, &rights) == -1 && errno != ENOSYS)
|
||||
err(1, "unable to limit capability rights");
|
||||
if (cap_ioctls_limit(out.fd, cmds, nitems(cmds)) == -1 &&
|
||||
errno != ENOSYS)
|
||||
err(1, "unable to limit capability rights");
|
||||
|
||||
if (in.fd != STDERR_FILENO && out.fd != STDERR_FILENO) {
|
||||
if (caph_limit_stderr() == -1)
|
||||
err(1, "unable to limit capability rights");
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate space for the input and output buffers. If not doing
|
||||
* record oriented I/O, only need a single buffer.
|
||||
|
@ -120,11 +120,12 @@ command(KINFO *k, VARENT *ve)
|
||||
if (cflag) {
|
||||
/* If it is the last field, then don't pad */
|
||||
if (STAILQ_NEXT(ve, next_ve) == NULL) {
|
||||
asprintf(&str, "%s%s%s%s",
|
||||
asprintf(&str, "%s%s%s%s%s",
|
||||
k->ki_d.prefix ? k->ki_d.prefix : "",
|
||||
k->ki_p->ki_comm,
|
||||
(showthreads && k->ki_p->ki_numthreads > 1) ? "/" : "",
|
||||
(showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_tdname : "");
|
||||
(showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_tdname : "",
|
||||
(showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_moretdname : "");
|
||||
} else
|
||||
str = strdup(k->ki_p->ki_comm);
|
||||
|
||||
@ -172,14 +173,16 @@ ucomm(KINFO *k, VARENT *ve)
|
||||
char *str;
|
||||
|
||||
if (STAILQ_NEXT(ve, next_ve) == NULL) { /* last field, don't pad */
|
||||
asprintf(&str, "%s%s%s%s",
|
||||
asprintf(&str, "%s%s%s%s%s",
|
||||
k->ki_d.prefix ? k->ki_d.prefix : "",
|
||||
k->ki_p->ki_comm,
|
||||
(showthreads && k->ki_p->ki_numthreads > 1) ? "/" : "",
|
||||
(showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_tdname : "");
|
||||
(showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_tdname : "",
|
||||
(showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_moretdname : "");
|
||||
} else {
|
||||
if (showthreads && k->ki_p->ki_numthreads > 1)
|
||||
asprintf(&str, "%s/%s", k->ki_p->ki_comm, k->ki_p->ki_tdname);
|
||||
asprintf(&str, "%s/%s%s", k->ki_p->ki_comm,
|
||||
k->ki_p->ki_tdname, k->ki_p->ki_moretdname);
|
||||
else
|
||||
str = strdup(k->ki_p->ki_comm);
|
||||
}
|
||||
@ -192,7 +195,8 @@ tdnam(KINFO *k, VARENT *ve __unused)
|
||||
char *str;
|
||||
|
||||
if (showthreads && k->ki_p->ki_numthreads > 1)
|
||||
str = strdup(k->ki_p->ki_tdname);
|
||||
asprintf(&str, "%s%s", k->ki_p->ki_tdname,
|
||||
k->ki_p->ki_moretdname);
|
||||
else
|
||||
str = strdup(" ");
|
||||
|
||||
|
@ -38,9 +38,6 @@
|
||||
#define PR_RLC 0x0001
|
||||
#define PR_KLC 0x0002
|
||||
|
||||
#define PGRAB_RDONLY O_RDONLY
|
||||
#define PGRAB_FORCE 0
|
||||
|
||||
#include_next <libproc.h>
|
||||
|
||||
#endif
|
||||
|
@ -56,7 +56,7 @@ prov.h: prov.d
|
||||
$dtrace -h -s prov.d
|
||||
|
||||
prov.o: prov.d main.o
|
||||
$dtrace -G -32 -s prov.d main.o
|
||||
$dtrace -G -s prov.d main.o
|
||||
EOF
|
||||
|
||||
cat > prov.d <<EOF
|
||||
|
@ -45,7 +45,7 @@ EOF
|
||||
spinny()
|
||||
{
|
||||
while true; do
|
||||
/usr/bin/date > /dev/null
|
||||
/bin/date > /dev/null
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ EOF
|
||||
spinny()
|
||||
{
|
||||
while true; do
|
||||
/usr/bin/date > /dev/null
|
||||
/bin/date > /dev/null
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ EOF
|
||||
spinny()
|
||||
{
|
||||
while true; do
|
||||
/usr/bin/date > /dev/null
|
||||
/bin/date > /dev/null
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -729,8 +729,13 @@ dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
|
||||
(void) snprintf(provname, sizeof (provname), "pid%d", (int)pid);
|
||||
|
||||
if (gmatch(provname, pdp->dtpd_provider) != 0) {
|
||||
#ifdef __FreeBSD__
|
||||
if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL)
|
||||
#else
|
||||
if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE,
|
||||
0)) == NULL) {
|
||||
0)) == NULL)
|
||||
#endif
|
||||
{
|
||||
(void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB,
|
||||
"failed to grab process %d", (int)pid);
|
||||
return (-1);
|
||||
|
@ -34,6 +34,9 @@
|
||||
* Functions sorted alphabetically.
|
||||
*/
|
||||
#define PR_LMID_EVERY 0
|
||||
#define PGRAB_RDONLY PATTACH_RDONLY
|
||||
#define PGRAB_FORCE PATTACH_FORCE
|
||||
|
||||
#define Psetrun(p, a1, a2) proc_continue((p))
|
||||
#define Pxlookup_by_addr(p, a, n, s, sym, i) \
|
||||
proc_addr2sym(p, a, n, s, sym)
|
||||
@ -44,7 +47,7 @@
|
||||
#define Pdelbkpt proc_bkptdel
|
||||
#define Pgrab_error strerror
|
||||
#define Plmid(p, a, l) (-1)
|
||||
#define Plmid_to_map(p, l, o) proc_obj2map((p), (o))
|
||||
#define Plmid_to_map(p, l, o) proc_name2map(p, o)
|
||||
#define Plookup_by_addr proc_addr2sym
|
||||
#define Pname_to_ctf(p, obj) (ctf_file_t *)proc_name2ctf(p, obj)
|
||||
#define Pname_to_map proc_name2map
|
||||
|
@ -70,7 +70,7 @@ runtest()
|
||||
err.*.ksh|tst.*.ksh)
|
||||
expr "$TFILE" : 'err.*' >/dev/null && exstatus=1
|
||||
|
||||
ksh "$TFILE" /usr/sbin/dtrace >$STDOUT 2>$STDERR
|
||||
tst=$TFILE ksh "$TFILE" /usr/sbin/dtrace >$STDOUT 2>$STDERR
|
||||
status=$?
|
||||
|
||||
if [ $status -ne $exstatus ]; then
|
||||
|
@ -128,9 +128,6 @@ exclude EXFAIL common/ip/tst.ipv4remoteicmp.ksh
|
||||
exclude EXFAIL common/ip/tst.localtcpstate.ksh
|
||||
exclude EXFAIL common/ip/tst.remotetcpstate.ksh
|
||||
|
||||
# Depends on the number of probes in /bin/sh and the current DOF limit.
|
||||
exclude EXFAIL common/pid/err.D_PROC_CREATEFAIL.many.d
|
||||
|
||||
# Tries to enable pid$target:libc::entry, though there's no "libc" module.
|
||||
# Currently unsure as to whether this might be a libproc bug.
|
||||
exclude EXFAIL common/pid/tst.probemod.ksh
|
||||
|
@ -2112,7 +2112,7 @@ dwarf_reg(unsigned int mach, unsigned int reg)
|
||||
static void
|
||||
dump_ehdr(struct readelf *re)
|
||||
{
|
||||
size_t shnum, shstrndx;
|
||||
size_t phnum, shnum, shstrndx;
|
||||
int i;
|
||||
|
||||
printf("ELF Header:\n");
|
||||
@ -2174,7 +2174,13 @@ dump_ehdr(struct readelf *re)
|
||||
re->ehdr.e_phentsize);
|
||||
|
||||
/* e_phnum. */
|
||||
printf("%-37s%u\n", " Number of program headers:", re->ehdr.e_phnum);
|
||||
printf("%-37s%u", " Number of program headers:", re->ehdr.e_phnum);
|
||||
if (re->ehdr.e_phnum == PN_XNUM) {
|
||||
/* Extended program header numbering is in use. */
|
||||
if (elf_getphnum(re->elf, &phnum))
|
||||
printf(" (%zu)", phnum);
|
||||
}
|
||||
putchar('\n');
|
||||
|
||||
/* e_shentsize. */
|
||||
printf("%-37s%u (bytes)\n", " Size of section headers:",
|
||||
@ -6551,14 +6557,15 @@ load_sections(struct readelf *re)
|
||||
}
|
||||
if ((name = elf_strptr(re->elf, shstrndx, sh.sh_name)) == NULL) {
|
||||
(void) elf_errno();
|
||||
name = "ERROR";
|
||||
name = "<no-name>";
|
||||
}
|
||||
if ((ndx = elf_ndxscn(scn)) == SHN_UNDEF) {
|
||||
if ((elferr = elf_errno()) != 0)
|
||||
if ((elferr = elf_errno()) != 0) {
|
||||
warnx("elf_ndxscn failed: %s",
|
||||
elf_errmsg(elferr));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ndx >= re->shnum) {
|
||||
warnx("section index of '%s' out of range", name);
|
||||
continue;
|
||||
|
@ -4,6 +4,33 @@ brevity. Much more detail can be found in the git revision history:
|
||||
|
||||
https://github.com/jemalloc/jemalloc
|
||||
|
||||
* 4.4.0 (December 3, 2016)
|
||||
|
||||
New features:
|
||||
- Add configure support for *-*-linux-android. (@cferris1000, @jasone)
|
||||
- Add the --disable-syscall configure option, for use on systems that place
|
||||
security-motivated limitations on syscall(2). (@jasone)
|
||||
- Add support for Debian GNU/kFreeBSD. (@thesam)
|
||||
|
||||
Optimizations:
|
||||
- Add extent serial numbers and use them where appropriate as a sort key that
|
||||
is higher priority than address, so that the allocation policy prefers older
|
||||
extents. This tends to improve locality (decrease fragmentation) when
|
||||
memory grows downward. (@jasone)
|
||||
- Refactor madvise(2) configuration so that MADV_FREE is detected and utilized
|
||||
on Linux 4.5 and newer. (@jasone)
|
||||
- Mark partially purged arena chunks as non-huge-page. This improves
|
||||
interaction with Linux's transparent huge page functionality. (@jasone)
|
||||
|
||||
Bug fixes:
|
||||
- Fix size class computations for edge conditions involving extremely large
|
||||
allocations. This regression was first released in 4.0.0. (@jasone,
|
||||
@ingvarha)
|
||||
- Remove overly restrictive assertions related to the cactive statistic. This
|
||||
regression was first released in 4.1.0. (@jasone)
|
||||
- Implement a more reliable detection scheme for os_unfair_lock on macOS.
|
||||
(@jszakmeister)
|
||||
|
||||
* 4.3.1 (November 7, 2016)
|
||||
|
||||
Bug fixes:
|
||||
|
@ -1,5 +1,5 @@
|
||||
diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in
|
||||
index 3d2e721..b361db2 100644
|
||||
index d9c8345..9898c3c 100644
|
||||
--- a/doc/jemalloc.xml.in
|
||||
+++ b/doc/jemalloc.xml.in
|
||||
@@ -53,11 +53,23 @@
|
||||
@ -47,10 +47,10 @@ index 3d2e721..b361db2 100644
|
||||
+ </refsect1>
|
||||
</refentry>
|
||||
diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h
|
||||
index f39ce54..a3ba55d 100644
|
||||
index ce4e602..35360b6 100644
|
||||
--- a/include/jemalloc/internal/arena.h
|
||||
+++ b/include/jemalloc/internal/arena.h
|
||||
@@ -719,8 +719,13 @@ arena_miscelm_get_mutable(arena_chunk_t *chunk, size_t pageind)
|
||||
@@ -730,8 +730,13 @@ arena_miscelm_get_mutable(arena_chunk_t *chunk, size_t pageind)
|
||||
JEMALLOC_ALWAYS_INLINE const arena_chunk_map_misc_t *
|
||||
arena_miscelm_get_const(const arena_chunk_t *chunk, size_t pageind)
|
||||
{
|
||||
@ -64,7 +64,7 @@ index f39ce54..a3ba55d 100644
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE size_t
|
||||
@@ -779,8 +784,13 @@ arena_mapbitsp_get_mutable(arena_chunk_t *chunk, size_t pageind)
|
||||
@@ -790,8 +795,13 @@ arena_mapbitsp_get_mutable(arena_chunk_t *chunk, size_t pageind)
|
||||
JEMALLOC_ALWAYS_INLINE const size_t *
|
||||
arena_mapbitsp_get_const(const arena_chunk_t *chunk, size_t pageind)
|
||||
{
|
||||
@ -79,7 +79,7 @@ index f39ce54..a3ba55d 100644
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE size_t
|
||||
diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in
|
||||
index fdc8fef..56a35a4 100644
|
||||
index e7ace7d..d86c61d 100644
|
||||
--- a/include/jemalloc/internal/jemalloc_internal.h.in
|
||||
+++ b/include/jemalloc/internal/jemalloc_internal.h.in
|
||||
@@ -8,6 +8,9 @@
|
||||
@ -144,10 +144,10 @@ index b442d2d..76518db 100644
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt
|
||||
index 87c8c9b..df576f6 100644
|
||||
index c1c6c40..c6395fd 100644
|
||||
--- a/include/jemalloc/internal/private_symbols.txt
|
||||
+++ b/include/jemalloc/internal/private_symbols.txt
|
||||
@@ -307,7 +307,6 @@ iralloct_realign
|
||||
@@ -310,7 +310,6 @@ iralloct_realign
|
||||
isalloc
|
||||
isdalloct
|
||||
isqalloc
|
||||
@ -335,7 +335,7 @@ index f943891..47d032c 100755
|
||||
+#include "jemalloc_FreeBSD.h"
|
||||
EOF
|
||||
diff --git a/src/jemalloc.c b/src/jemalloc.c
|
||||
index 38650ff..f659b55 100644
|
||||
index baead66..8a49f26 100644
|
||||
--- a/src/jemalloc.c
|
||||
+++ b/src/jemalloc.c
|
||||
@@ -4,6 +4,10 @@
|
||||
@ -349,7 +349,7 @@ index 38650ff..f659b55 100644
|
||||
/* Runtime configuration options. */
|
||||
const char *je_malloc_conf
|
||||
#ifndef _WIN32
|
||||
@@ -2756,6 +2760,107 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)
|
||||
@@ -2775,6 +2779,107 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)
|
||||
*/
|
||||
/******************************************************************************/
|
||||
/*
|
||||
@ -457,7 +457,7 @@ index 38650ff..f659b55 100644
|
||||
* The following functions are used by threading libraries for protection of
|
||||
* malloc during fork().
|
||||
*/
|
||||
@@ -2894,4 +2999,11 @@ jemalloc_postfork_child(void)
|
||||
@@ -2913,4 +3018,11 @@ jemalloc_postfork_child(void)
|
||||
ctl_postfork_child(tsd_tsdn(tsd));
|
||||
}
|
||||
|
||||
@ -516,7 +516,7 @@ index 6333e73..13f8d79 100644
|
||||
+#endif
|
||||
+}
|
||||
diff --git a/src/util.c b/src/util.c
|
||||
index 7905267..bee1c77 100644
|
||||
index dd8c236..a4ff287 100755
|
||||
--- a/src/util.c
|
||||
+++ b/src/util.c
|
||||
@@ -67,6 +67,22 @@ wrtmessage(void *cbopaque, const char *s)
|
||||
|
@ -1 +1 @@
|
||||
4.3.1-0-g0110fa8451af905affd77c3bea0d545fee2251b2
|
||||
4.4.0-0-gf1f76357313e7dcad7262f17a48ff0a2e005fcdc
|
||||
|
@ -2,12 +2,12 @@
|
||||
.\" Title: JEMALLOC
|
||||
.\" Author: Jason Evans
|
||||
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
|
||||
.\" Date: 11/08/2016
|
||||
.\" Date: 12/04/2016
|
||||
.\" Manual: User Manual
|
||||
.\" Source: jemalloc 4.3.1-0-g0110fa8451af905affd77c3bea0d545fee2251b2
|
||||
.\" Source: jemalloc 4.4.0-0-gf1f76357313e7dcad7262f17a48ff0a2e005fcdc
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "JEMALLOC" "3" "11/08/2016" "jemalloc 4.3.1-0-g0110fa8451af" "User Manual"
|
||||
.TH "JEMALLOC" "3" "12/04/2016" "jemalloc 4.4.0-0-gf1f76357313e" "User Manual"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
@ -31,7 +31,7 @@
|
||||
jemalloc \- general purpose memory allocation functions
|
||||
.SH "LIBRARY"
|
||||
.PP
|
||||
This manual describes jemalloc 4\&.3\&.1\-0\-g0110fa8451af905affd77c3bea0d545fee2251b2\&. More information can be found at the
|
||||
This manual describes jemalloc 4\&.4\&.0\-0\-gf1f76357313e7dcad7262f17a48ff0a2e005fcdc\&. More information can be found at the
|
||||
\m[blue]\fBjemalloc website\fR\m[]\&\s-2\u[1]\d\s+2\&.
|
||||
.PP
|
||||
The following configuration options are enabled in libc\*(Aqs built\-in jemalloc:
|
||||
@ -365,7 +365,7 @@ for (i = 0; i < nbins; i++) {
|
||||
|
||||
mib[2] = i;
|
||||
len = sizeof(bin_size);
|
||||
mallctlbymib(mib, miblen, &bin_size, &len, NULL, 0);
|
||||
mallctlbymib(mib, miblen, (void *)&bin_size, &len, NULL, 0);
|
||||
/* Do something with bin_size\&.\&.\&. */
|
||||
}
|
||||
.fi
|
||||
|
@ -190,6 +190,14 @@ struct arena_chunk_s {
|
||||
*/
|
||||
extent_node_t node;
|
||||
|
||||
/*
|
||||
* True if memory could be backed by transparent huge pages. This is
|
||||
* only directly relevant to Linux, since it is the only supported
|
||||
* platform on which jemalloc interacts with explicit transparent huge
|
||||
* page controls.
|
||||
*/
|
||||
bool hugepage;
|
||||
|
||||
/*
|
||||
* Map of pages within chunk that keeps track of free/large/small. The
|
||||
* first map_bias entries are omitted, since the chunk header does not
|
||||
@ -374,10 +382,12 @@ struct arena_s {
|
||||
|
||||
dss_prec_t dss_prec;
|
||||
|
||||
|
||||
/* Extant arena chunks. */
|
||||
ql_head(extent_node_t) achunks;
|
||||
|
||||
/* Extent serial number generator state. */
|
||||
size_t extent_sn_next;
|
||||
|
||||
/*
|
||||
* In order to avoid rapid chunk allocation/deallocation when an arena
|
||||
* oscillates right on the cusp of needing a new chunk, cache the most
|
||||
@ -453,9 +463,9 @@ struct arena_s {
|
||||
* orderings are needed, which is why there are two trees with the same
|
||||
* contents.
|
||||
*/
|
||||
extent_tree_t chunks_szad_cached;
|
||||
extent_tree_t chunks_szsnad_cached;
|
||||
extent_tree_t chunks_ad_cached;
|
||||
extent_tree_t chunks_szad_retained;
|
||||
extent_tree_t chunks_szsnad_retained;
|
||||
extent_tree_t chunks_ad_retained;
|
||||
|
||||
malloc_mutex_t chunks_mtx;
|
||||
@ -522,13 +532,13 @@ void arena_chunk_cache_maybe_remove(arena_t *arena, extent_node_t *node,
|
||||
extent_node_t *arena_node_alloc(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_node_dalloc(tsdn_t *tsdn, arena_t *arena, extent_node_t *node);
|
||||
void *arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
||||
size_t alignment, bool *zero);
|
||||
size_t alignment, size_t *sn, bool *zero);
|
||||
void arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, void *chunk,
|
||||
size_t usize);
|
||||
size_t usize, size_t sn);
|
||||
void arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena,
|
||||
void *chunk, size_t oldsize, size_t usize);
|
||||
void arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena,
|
||||
void *chunk, size_t oldsize, size_t usize);
|
||||
void *chunk, size_t oldsize, size_t usize, size_t sn);
|
||||
bool arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena,
|
||||
void *chunk, size_t oldsize, size_t usize, bool *zero);
|
||||
ssize_t arena_lg_dirty_mult_get(tsdn_t *tsdn, arena_t *arena);
|
||||
@ -601,6 +611,7 @@ void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
||||
unsigned arena_nthreads_get(arena_t *arena, bool internal);
|
||||
void arena_nthreads_inc(arena_t *arena, bool internal);
|
||||
void arena_nthreads_dec(arena_t *arena, bool internal);
|
||||
size_t arena_extent_sn_next(arena_t *arena);
|
||||
arena_t *arena_new(tsdn_t *tsdn, unsigned ind);
|
||||
void arena_boot(void);
|
||||
void arena_prefork0(tsdn_t *tsdn, arena_t *arena);
|
||||
|
@ -58,15 +58,16 @@ void chunk_deregister(const void *chunk, const extent_node_t *node);
|
||||
void *chunk_alloc_base(size_t size);
|
||||
void *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena,
|
||||
chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment,
|
||||
bool *zero, bool *commit, bool dalloc_node);
|
||||
size_t *sn, bool *zero, bool *commit, bool dalloc_node);
|
||||
void *chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena,
|
||||
chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment,
|
||||
bool *zero, bool *commit);
|
||||
size_t *sn, bool *zero, bool *commit);
|
||||
void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena,
|
||||
chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool committed);
|
||||
void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena,
|
||||
chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool zeroed,
|
||||
chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t sn,
|
||||
bool committed);
|
||||
void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena,
|
||||
chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t sn,
|
||||
bool zeroed, bool committed);
|
||||
bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena,
|
||||
chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset,
|
||||
size_t length);
|
||||
|
@ -18,6 +18,20 @@ struct extent_node_s {
|
||||
/* Total region size. */
|
||||
size_t en_size;
|
||||
|
||||
/*
|
||||
* Serial number (potentially non-unique).
|
||||
*
|
||||
* In principle serial numbers can wrap around on 32-bit systems if
|
||||
* JEMALLOC_MUNMAP is defined, but as long as comparison functions fall
|
||||
* back on address comparison for equal serial numbers, stable (if
|
||||
* imperfect) ordering is maintained.
|
||||
*
|
||||
* Serial numbers may not be unique even in the absence of wrap-around,
|
||||
* e.g. when splitting an extent and assigning the same serial number to
|
||||
* both resulting adjacent extents.
|
||||
*/
|
||||
size_t en_sn;
|
||||
|
||||
/*
|
||||
* The zeroed flag is used by chunk recycling code to track whether
|
||||
* memory is zero-filled.
|
||||
@ -45,8 +59,8 @@ struct extent_node_s {
|
||||
qr(extent_node_t) cc_link;
|
||||
|
||||
union {
|
||||
/* Linkage for the size/address-ordered tree. */
|
||||
rb_node(extent_node_t) szad_link;
|
||||
/* Linkage for the size/sn/address-ordered tree. */
|
||||
rb_node(extent_node_t) szsnad_link;
|
||||
|
||||
/* Linkage for arena's achunks, huge, and node_cache lists. */
|
||||
ql_elm(extent_node_t) ql_link;
|
||||
@ -61,7 +75,7 @@ typedef rb_tree(extent_node_t) extent_tree_t;
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
|
||||
rb_proto(, extent_tree_szad_, extent_tree_t, extent_node_t)
|
||||
rb_proto(, extent_tree_szsnad_, extent_tree_t, extent_node_t)
|
||||
|
||||
rb_proto(, extent_tree_ad_, extent_tree_t, extent_node_t)
|
||||
|
||||
@ -73,6 +87,7 @@ rb_proto(, extent_tree_ad_, extent_tree_t, extent_node_t)
|
||||
arena_t *extent_node_arena_get(const extent_node_t *node);
|
||||
void *extent_node_addr_get(const extent_node_t *node);
|
||||
size_t extent_node_size_get(const extent_node_t *node);
|
||||
size_t extent_node_sn_get(const extent_node_t *node);
|
||||
bool extent_node_zeroed_get(const extent_node_t *node);
|
||||
bool extent_node_committed_get(const extent_node_t *node);
|
||||
bool extent_node_achunk_get(const extent_node_t *node);
|
||||
@ -80,12 +95,13 @@ prof_tctx_t *extent_node_prof_tctx_get(const extent_node_t *node);
|
||||
void extent_node_arena_set(extent_node_t *node, arena_t *arena);
|
||||
void extent_node_addr_set(extent_node_t *node, void *addr);
|
||||
void extent_node_size_set(extent_node_t *node, size_t size);
|
||||
void extent_node_sn_set(extent_node_t *node, size_t sn);
|
||||
void extent_node_zeroed_set(extent_node_t *node, bool zeroed);
|
||||
void extent_node_committed_set(extent_node_t *node, bool committed);
|
||||
void extent_node_achunk_set(extent_node_t *node, bool achunk);
|
||||
void extent_node_prof_tctx_set(extent_node_t *node, prof_tctx_t *tctx);
|
||||
void extent_node_init(extent_node_t *node, arena_t *arena, void *addr,
|
||||
size_t size, bool zeroed, bool committed);
|
||||
size_t size, size_t sn, bool zeroed, bool committed);
|
||||
void extent_node_dirty_linkage_init(extent_node_t *node);
|
||||
void extent_node_dirty_insert(extent_node_t *node,
|
||||
arena_runs_dirty_link_t *runs_dirty, extent_node_t *chunks_dirty);
|
||||
@ -114,6 +130,13 @@ extent_node_size_get(const extent_node_t *node)
|
||||
return (node->en_size);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE size_t
|
||||
extent_node_sn_get(const extent_node_t *node)
|
||||
{
|
||||
|
||||
return (node->en_sn);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
extent_node_zeroed_get(const extent_node_t *node)
|
||||
{
|
||||
@ -164,6 +187,13 @@ extent_node_size_set(extent_node_t *node, size_t size)
|
||||
node->en_size = size;
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_sn_set(extent_node_t *node, size_t sn)
|
||||
{
|
||||
|
||||
node->en_sn = sn;
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_zeroed_set(extent_node_t *node, bool zeroed)
|
||||
{
|
||||
@ -194,12 +224,13 @@ extent_node_prof_tctx_set(extent_node_t *node, prof_tctx_t *tctx)
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_init(extent_node_t *node, arena_t *arena, void *addr, size_t size,
|
||||
bool zeroed, bool committed)
|
||||
size_t sn, bool zeroed, bool committed)
|
||||
{
|
||||
|
||||
extent_node_arena_set(node, arena);
|
||||
extent_node_addr_set(node, addr);
|
||||
extent_node_size_set(node, size);
|
||||
extent_node_sn_set(node, sn);
|
||||
extent_node_zeroed_set(node, zeroed);
|
||||
extent_node_committed_set(node, committed);
|
||||
extent_node_achunk_set(node, false);
|
||||
|
@ -334,7 +334,7 @@ typedef unsigned szind_t;
|
||||
|
||||
/* Return the nearest aligned address at or below a. */
|
||||
#define ALIGNMENT_ADDR2BASE(a, alignment) \
|
||||
((void *)((uintptr_t)(a) & (-(alignment))))
|
||||
((void *)((uintptr_t)(a) & ((~(alignment)) + 1)))
|
||||
|
||||
/* Return the offset between a and the nearest aligned address at or below a. */
|
||||
#define ALIGNMENT_ADDR2OFFSET(a, alignment) \
|
||||
@ -342,7 +342,7 @@ typedef unsigned szind_t;
|
||||
|
||||
/* Return the smallest alignment multiple that is >= s. */
|
||||
#define ALIGNMENT_CEILING(s, alignment) \
|
||||
(((s) + (alignment - 1)) & (-(alignment)))
|
||||
(((s) + (alignment - 1)) & ((~(alignment)) + 1))
|
||||
|
||||
/* Declare a variable-length array. */
|
||||
#if __STDC_VERSION__ < 199901L
|
||||
|
@ -56,11 +56,6 @@
|
||||
*/
|
||||
#define JEMALLOC_HAVE_BUILTIN_CLZ
|
||||
|
||||
/*
|
||||
* Defined if madvise(2) is available.
|
||||
*/
|
||||
#define JEMALLOC_HAVE_MADVISE
|
||||
|
||||
/*
|
||||
* Defined if os_unfair_lock_*() functions are available, as provided by Darwin.
|
||||
*/
|
||||
@ -72,8 +67,8 @@
|
||||
*/
|
||||
/* #undef JEMALLOC_OSSPIN */
|
||||
|
||||
/* Defined if syscall(2) is available. */
|
||||
#define JEMALLOC_HAVE_SYSCALL
|
||||
/* Defined if syscall(2) is usable. */
|
||||
#define JEMALLOC_USE_SYSCALL
|
||||
|
||||
/*
|
||||
* Defined if secure_getenv(3) is available.
|
||||
@ -85,6 +80,9 @@
|
||||
*/
|
||||
#define JEMALLOC_HAVE_ISSETUGID
|
||||
|
||||
/* Defined if pthread_atfork(3) is available. */
|
||||
#define JEMALLOC_HAVE_PTHREAD_ATFORK
|
||||
|
||||
/*
|
||||
* Defined if clock_gettime(CLOCK_MONOTONIC_COARSE, ...) is available.
|
||||
*/
|
||||
@ -253,18 +251,26 @@
|
||||
#define JEMALLOC_SYSCTL_VM_OVERCOMMIT
|
||||
/* #undef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY */
|
||||
|
||||
/* Defined if madvise(2) is available. */
|
||||
#define JEMALLOC_HAVE_MADVISE
|
||||
|
||||
/*
|
||||
* Methods for purging unused pages differ between operating systems.
|
||||
*
|
||||
* madvise(..., MADV_DONTNEED) : On Linux, this immediately discards pages,
|
||||
* such that new pages will be demand-zeroed if
|
||||
* the address region is later touched.
|
||||
* madvise(..., MADV_FREE) : On FreeBSD and Darwin, this marks pages as being
|
||||
* unused, such that they will be discarded rather
|
||||
* than swapped out.
|
||||
* madvise(..., MADV_FREE) : This marks pages as being unused, such that they
|
||||
* will be discarded rather than swapped out.
|
||||
* madvise(..., MADV_DONTNEED) : This immediately discards pages, such that
|
||||
* new pages will be demand-zeroed if the
|
||||
* address region is later touched.
|
||||
*/
|
||||
/* #undef JEMALLOC_PURGE_MADVISE_DONTNEED */
|
||||
#define JEMALLOC_PURGE_MADVISE_FREE
|
||||
#define JEMALLOC_PURGE_MADVISE_DONTNEED
|
||||
|
||||
/*
|
||||
* Defined if transparent huge pages are supported via the MADV_[NO]HUGEPAGE
|
||||
* arguments to madvise(2).
|
||||
*/
|
||||
/* #undef JEMALLOC_THP */
|
||||
|
||||
/* Define if operating system has alloca.h header. */
|
||||
/* #undef JEMALLOC_HAS_ALLOCA_H */
|
||||
|
@ -16,6 +16,8 @@ void *pages_trim(void *addr, size_t alloc_size, size_t leadsize,
|
||||
bool pages_commit(void *addr, size_t size);
|
||||
bool pages_decommit(void *addr, size_t size);
|
||||
bool pages_purge(void *addr, size_t size);
|
||||
bool pages_huge(void *addr, size_t size);
|
||||
bool pages_nohuge(void *addr, size_t size);
|
||||
void pages_boot(void);
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
|
@ -36,6 +36,7 @@
|
||||
#define arena_decay_time_set JEMALLOC_N(arena_decay_time_set)
|
||||
#define arena_dss_prec_get JEMALLOC_N(arena_dss_prec_get)
|
||||
#define arena_dss_prec_set JEMALLOC_N(arena_dss_prec_set)
|
||||
#define arena_extent_sn_next JEMALLOC_N(arena_extent_sn_next)
|
||||
#define arena_get JEMALLOC_N(arena_get)
|
||||
#define arena_ichoose JEMALLOC_N(arena_ichoose)
|
||||
#define arena_init JEMALLOC_N(arena_init)
|
||||
@ -218,6 +219,8 @@
|
||||
#define extent_node_prof_tctx_set JEMALLOC_N(extent_node_prof_tctx_set)
|
||||
#define extent_node_size_get JEMALLOC_N(extent_node_size_get)
|
||||
#define extent_node_size_set JEMALLOC_N(extent_node_size_set)
|
||||
#define extent_node_sn_get JEMALLOC_N(extent_node_sn_get)
|
||||
#define extent_node_sn_set JEMALLOC_N(extent_node_sn_set)
|
||||
#define extent_node_zeroed_get JEMALLOC_N(extent_node_zeroed_get)
|
||||
#define extent_node_zeroed_set JEMALLOC_N(extent_node_zeroed_set)
|
||||
#define extent_tree_ad_destroy JEMALLOC_N(extent_tree_ad_destroy)
|
||||
@ -239,25 +242,25 @@
|
||||
#define extent_tree_ad_reverse_iter_recurse JEMALLOC_N(extent_tree_ad_reverse_iter_recurse)
|
||||
#define extent_tree_ad_reverse_iter_start JEMALLOC_N(extent_tree_ad_reverse_iter_start)
|
||||
#define extent_tree_ad_search JEMALLOC_N(extent_tree_ad_search)
|
||||
#define extent_tree_szad_destroy JEMALLOC_N(extent_tree_szad_destroy)
|
||||
#define extent_tree_szad_destroy_recurse JEMALLOC_N(extent_tree_szad_destroy_recurse)
|
||||
#define extent_tree_szad_empty JEMALLOC_N(extent_tree_szad_empty)
|
||||
#define extent_tree_szad_first JEMALLOC_N(extent_tree_szad_first)
|
||||
#define extent_tree_szad_insert JEMALLOC_N(extent_tree_szad_insert)
|
||||
#define extent_tree_szad_iter JEMALLOC_N(extent_tree_szad_iter)
|
||||
#define extent_tree_szad_iter_recurse JEMALLOC_N(extent_tree_szad_iter_recurse)
|
||||
#define extent_tree_szad_iter_start JEMALLOC_N(extent_tree_szad_iter_start)
|
||||
#define extent_tree_szad_last JEMALLOC_N(extent_tree_szad_last)
|
||||
#define extent_tree_szad_new JEMALLOC_N(extent_tree_szad_new)
|
||||
#define extent_tree_szad_next JEMALLOC_N(extent_tree_szad_next)
|
||||
#define extent_tree_szad_nsearch JEMALLOC_N(extent_tree_szad_nsearch)
|
||||
#define extent_tree_szad_prev JEMALLOC_N(extent_tree_szad_prev)
|
||||
#define extent_tree_szad_psearch JEMALLOC_N(extent_tree_szad_psearch)
|
||||
#define extent_tree_szad_remove JEMALLOC_N(extent_tree_szad_remove)
|
||||
#define extent_tree_szad_reverse_iter JEMALLOC_N(extent_tree_szad_reverse_iter)
|
||||
#define extent_tree_szad_reverse_iter_recurse JEMALLOC_N(extent_tree_szad_reverse_iter_recurse)
|
||||
#define extent_tree_szad_reverse_iter_start JEMALLOC_N(extent_tree_szad_reverse_iter_start)
|
||||
#define extent_tree_szad_search JEMALLOC_N(extent_tree_szad_search)
|
||||
#define extent_tree_szsnad_destroy JEMALLOC_N(extent_tree_szsnad_destroy)
|
||||
#define extent_tree_szsnad_destroy_recurse JEMALLOC_N(extent_tree_szsnad_destroy_recurse)
|
||||
#define extent_tree_szsnad_empty JEMALLOC_N(extent_tree_szsnad_empty)
|
||||
#define extent_tree_szsnad_first JEMALLOC_N(extent_tree_szsnad_first)
|
||||
#define extent_tree_szsnad_insert JEMALLOC_N(extent_tree_szsnad_insert)
|
||||
#define extent_tree_szsnad_iter JEMALLOC_N(extent_tree_szsnad_iter)
|
||||
#define extent_tree_szsnad_iter_recurse JEMALLOC_N(extent_tree_szsnad_iter_recurse)
|
||||
#define extent_tree_szsnad_iter_start JEMALLOC_N(extent_tree_szsnad_iter_start)
|
||||
#define extent_tree_szsnad_last JEMALLOC_N(extent_tree_szsnad_last)
|
||||
#define extent_tree_szsnad_new JEMALLOC_N(extent_tree_szsnad_new)
|
||||
#define extent_tree_szsnad_next JEMALLOC_N(extent_tree_szsnad_next)
|
||||
#define extent_tree_szsnad_nsearch JEMALLOC_N(extent_tree_szsnad_nsearch)
|
||||
#define extent_tree_szsnad_prev JEMALLOC_N(extent_tree_szsnad_prev)
|
||||
#define extent_tree_szsnad_psearch JEMALLOC_N(extent_tree_szsnad_psearch)
|
||||
#define extent_tree_szsnad_remove JEMALLOC_N(extent_tree_szsnad_remove)
|
||||
#define extent_tree_szsnad_reverse_iter JEMALLOC_N(extent_tree_szsnad_reverse_iter)
|
||||
#define extent_tree_szsnad_reverse_iter_recurse JEMALLOC_N(extent_tree_szsnad_reverse_iter_recurse)
|
||||
#define extent_tree_szsnad_reverse_iter_start JEMALLOC_N(extent_tree_szsnad_reverse_iter_start)
|
||||
#define extent_tree_szsnad_search JEMALLOC_N(extent_tree_szsnad_search)
|
||||
#define ffs_llu JEMALLOC_N(ffs_llu)
|
||||
#define ffs_lu JEMALLOC_N(ffs_lu)
|
||||
#define ffs_u JEMALLOC_N(ffs_u)
|
||||
@ -393,7 +396,9 @@
|
||||
#define pages_boot JEMALLOC_N(pages_boot)
|
||||
#define pages_commit JEMALLOC_N(pages_commit)
|
||||
#define pages_decommit JEMALLOC_N(pages_decommit)
|
||||
#define pages_huge JEMALLOC_N(pages_huge)
|
||||
#define pages_map JEMALLOC_N(pages_map)
|
||||
#define pages_nohuge JEMALLOC_N(pages_nohuge)
|
||||
#define pages_purge JEMALLOC_N(pages_purge)
|
||||
#define pages_trim JEMALLOC_N(pages_trim)
|
||||
#define pages_unmap JEMALLOC_N(pages_unmap)
|
||||
|
@ -175,25 +175,21 @@ stats_cactive_get(void)
|
||||
JEMALLOC_INLINE void
|
||||
stats_cactive_add(size_t size)
|
||||
{
|
||||
UNUSED size_t cactive;
|
||||
|
||||
assert(size > 0);
|
||||
assert((size & chunksize_mask) == 0);
|
||||
|
||||
cactive = atomic_add_z(&stats_cactive, size);
|
||||
assert(cactive - size < cactive);
|
||||
atomic_add_z(&stats_cactive, size);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
stats_cactive_sub(size_t size)
|
||||
{
|
||||
UNUSED size_t cactive;
|
||||
|
||||
assert(size > 0);
|
||||
assert((size & chunksize_mask) == 0);
|
||||
|
||||
cactive = atomic_sub_z(&stats_cactive, size);
|
||||
assert(cactive + size > cactive);
|
||||
atomic_sub_z(&stats_cactive, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -41,8 +41,12 @@
|
||||
#define MALLOC_PRINTF_BUFSIZE 4096
|
||||
|
||||
/* Junk fill patterns. */
|
||||
#ifndef JEMALLOC_ALLOC_JUNK
|
||||
# define JEMALLOC_ALLOC_JUNK ((uint8_t)0xa5)
|
||||
#endif
|
||||
#ifndef JEMALLOC_FREE_JUNK
|
||||
# define JEMALLOC_FREE_JUNK ((uint8_t)0x5a)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Wrap a cpp argument that contains commas such that it isn't broken up into
|
||||
|
@ -36,13 +36,25 @@
|
||||
zero); \
|
||||
} \
|
||||
} while (0)
|
||||
#define JEMALLOC_VALGRIND_REALLOC(maybe_moved, tsdn, ptr, usize, \
|
||||
ptr_maybe_null, old_ptr, old_usize, old_rzsize, old_ptr_maybe_null, \
|
||||
zero) do { \
|
||||
#define JEMALLOC_VALGRIND_REALLOC_MOVED_no(ptr, old_ptr) \
|
||||
(false)
|
||||
#define JEMALLOC_VALGRIND_REALLOC_MOVED_maybe(ptr, old_ptr) \
|
||||
((ptr) != (old_ptr))
|
||||
#define JEMALLOC_VALGRIND_REALLOC_PTR_NULL_no(ptr) \
|
||||
(false)
|
||||
#define JEMALLOC_VALGRIND_REALLOC_PTR_NULL_maybe(ptr) \
|
||||
(ptr == NULL)
|
||||
#define JEMALLOC_VALGRIND_REALLOC_OLD_PTR_NULL_no(old_ptr) \
|
||||
(false)
|
||||
#define JEMALLOC_VALGRIND_REALLOC_OLD_PTR_NULL_maybe(old_ptr) \
|
||||
(old_ptr == NULL)
|
||||
#define JEMALLOC_VALGRIND_REALLOC(moved, tsdn, ptr, usize, ptr_null, \
|
||||
old_ptr, old_usize, old_rzsize, old_ptr_null, zero) do { \
|
||||
if (unlikely(in_valgrind)) { \
|
||||
size_t rzsize = p2rz(tsdn, ptr); \
|
||||
\
|
||||
if (!maybe_moved || ptr == old_ptr) { \
|
||||
if (!JEMALLOC_VALGRIND_REALLOC_MOVED_##moved(ptr, \
|
||||
old_ptr)) { \
|
||||
VALGRIND_RESIZEINPLACE_BLOCK(ptr, old_usize, \
|
||||
usize, rzsize); \
|
||||
if (zero && old_usize < usize) { \
|
||||
@ -51,11 +63,13 @@
|
||||
old_usize), usize - old_usize); \
|
||||
} \
|
||||
} else { \
|
||||
if (!old_ptr_maybe_null || old_ptr != NULL) { \
|
||||
if (!JEMALLOC_VALGRIND_REALLOC_OLD_PTR_NULL_## \
|
||||
old_ptr_null(old_ptr)) { \
|
||||
valgrind_freelike_block(old_ptr, \
|
||||
old_rzsize); \
|
||||
} \
|
||||
if (!ptr_maybe_null || ptr != NULL) { \
|
||||
if (!JEMALLOC_VALGRIND_REALLOC_PTR_NULL_## \
|
||||
ptr_null(ptr)) { \
|
||||
size_t copy_size = (old_usize < usize) \
|
||||
? old_usize : usize; \
|
||||
size_t tail_size = usize - copy_size; \
|
||||
|
@ -87,12 +87,12 @@ extern "C" {
|
||||
#include <limits.h>
|
||||
#include <strings.h>
|
||||
|
||||
#define JEMALLOC_VERSION "4.3.1-0-g0110fa8451af905affd77c3bea0d545fee2251b2"
|
||||
#define JEMALLOC_VERSION "4.4.0-0-gf1f76357313e7dcad7262f17a48ff0a2e005fcdc"
|
||||
#define JEMALLOC_VERSION_MAJOR 4
|
||||
#define JEMALLOC_VERSION_MINOR 3
|
||||
#define JEMALLOC_VERSION_BUGFIX 1
|
||||
#define JEMALLOC_VERSION_MINOR 4
|
||||
#define JEMALLOC_VERSION_BUGFIX 0
|
||||
#define JEMALLOC_VERSION_NREV 0
|
||||
#define JEMALLOC_VERSION_GID "0110fa8451af905affd77c3bea0d545fee2251b2"
|
||||
#define JEMALLOC_VERSION_GID "f1f76357313e7dcad7262f17a48ff0a2e005fcdc"
|
||||
|
||||
# define MALLOCX_LG_ALIGN(la) ((int)(la))
|
||||
# if LG_SIZEOF_PTR == 2
|
||||
|
@ -38,8 +38,8 @@ static void arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, arena_run_t *run,
|
||||
bool dirty, bool cleaned, bool decommitted);
|
||||
static void arena_dalloc_bin_run(tsdn_t *tsdn, arena_t *arena,
|
||||
arena_chunk_t *chunk, arena_run_t *run, arena_bin_t *bin);
|
||||
static void arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk,
|
||||
arena_run_t *run, arena_bin_t *bin);
|
||||
static void arena_bin_lower_run(arena_t *arena, arena_run_t *run,
|
||||
arena_bin_t *bin);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@ -55,8 +55,31 @@ arena_miscelm_size_get(const arena_chunk_map_misc_t *miscelm)
|
||||
return (arena_mapbits_size_decode(mapbits));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE_C const extent_node_t *
|
||||
arena_miscelm_extent_get(const arena_chunk_map_misc_t *miscelm)
|
||||
{
|
||||
arena_chunk_t *chunk;
|
||||
|
||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm);
|
||||
return (&chunk->node);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE_C int
|
||||
arena_run_addr_comp(const arena_chunk_map_misc_t *a,
|
||||
arena_sn_comp(const arena_chunk_map_misc_t *a, const arena_chunk_map_misc_t *b)
|
||||
{
|
||||
size_t a_sn, b_sn;
|
||||
|
||||
assert(a != NULL);
|
||||
assert(b != NULL);
|
||||
|
||||
a_sn = extent_node_sn_get(arena_miscelm_extent_get(a));
|
||||
b_sn = extent_node_sn_get(arena_miscelm_extent_get(b));
|
||||
|
||||
return ((a_sn > b_sn) - (a_sn < b_sn));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE_C int
|
||||
arena_ad_comp(const arena_chunk_map_misc_t *a,
|
||||
const arena_chunk_map_misc_t *b)
|
||||
{
|
||||
uintptr_t a_miscelm = (uintptr_t)a;
|
||||
@ -68,9 +91,26 @@ arena_run_addr_comp(const arena_chunk_map_misc_t *a,
|
||||
return ((a_miscelm > b_miscelm) - (a_miscelm < b_miscelm));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE_C int
|
||||
arena_snad_comp(const arena_chunk_map_misc_t *a,
|
||||
const arena_chunk_map_misc_t *b)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(a != NULL);
|
||||
assert(b != NULL);
|
||||
|
||||
ret = arena_sn_comp(a, b);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
ret = arena_ad_comp(a, b);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Generate pairing heap functions. */
|
||||
ph_gen(static UNUSED, arena_run_heap_, arena_run_heap_t, arena_chunk_map_misc_t,
|
||||
ph_link, arena_run_addr_comp)
|
||||
ph_link, arena_snad_comp)
|
||||
|
||||
#ifdef JEMALLOC_JET
|
||||
#undef run_quantize_floor
|
||||
@ -529,7 +569,7 @@ arena_chunk_init_spare(arena_t *arena)
|
||||
|
||||
static bool
|
||||
arena_chunk_register(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk,
|
||||
bool zero)
|
||||
size_t sn, bool zero)
|
||||
{
|
||||
|
||||
/*
|
||||
@ -538,7 +578,7 @@ arena_chunk_register(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk,
|
||||
* of runs is tracked individually, and upon chunk deallocation the
|
||||
* entire chunk is in a consistent commit state.
|
||||
*/
|
||||
extent_node_init(&chunk->node, arena, chunk, chunksize, zero, true);
|
||||
extent_node_init(&chunk->node, arena, chunk, chunksize, sn, zero, true);
|
||||
extent_node_achunk_set(&chunk->node, true);
|
||||
return (chunk_register(tsdn, chunk, &chunk->node));
|
||||
}
|
||||
@ -548,28 +588,30 @@ arena_chunk_alloc_internal_hard(tsdn_t *tsdn, arena_t *arena,
|
||||
chunk_hooks_t *chunk_hooks, bool *zero, bool *commit)
|
||||
{
|
||||
arena_chunk_t *chunk;
|
||||
size_t sn;
|
||||
|
||||
malloc_mutex_unlock(tsdn, &arena->lock);
|
||||
|
||||
chunk = (arena_chunk_t *)chunk_alloc_wrapper(tsdn, arena, chunk_hooks,
|
||||
NULL, chunksize, chunksize, zero, commit);
|
||||
NULL, chunksize, chunksize, &sn, zero, commit);
|
||||
if (chunk != NULL && !*commit) {
|
||||
/* Commit header. */
|
||||
if (chunk_hooks->commit(chunk, chunksize, 0, map_bias <<
|
||||
LG_PAGE, arena->ind)) {
|
||||
chunk_dalloc_wrapper(tsdn, arena, chunk_hooks,
|
||||
(void *)chunk, chunksize, *zero, *commit);
|
||||
(void *)chunk, chunksize, sn, *zero, *commit);
|
||||
chunk = NULL;
|
||||
}
|
||||
}
|
||||
if (chunk != NULL && arena_chunk_register(tsdn, arena, chunk, *zero)) {
|
||||
if (chunk != NULL && arena_chunk_register(tsdn, arena, chunk, sn,
|
||||
*zero)) {
|
||||
if (!*commit) {
|
||||
/* Undo commit of header. */
|
||||
chunk_hooks->decommit(chunk, chunksize, 0, map_bias <<
|
||||
LG_PAGE, arena->ind);
|
||||
}
|
||||
chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, (void *)chunk,
|
||||
chunksize, *zero, *commit);
|
||||
chunksize, sn, *zero, *commit);
|
||||
chunk = NULL;
|
||||
}
|
||||
|
||||
@ -583,13 +625,14 @@ arena_chunk_alloc_internal(tsdn_t *tsdn, arena_t *arena, bool *zero,
|
||||
{
|
||||
arena_chunk_t *chunk;
|
||||
chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER;
|
||||
size_t sn;
|
||||
|
||||
chunk = chunk_alloc_cache(tsdn, arena, &chunk_hooks, NULL, chunksize,
|
||||
chunksize, zero, commit, true);
|
||||
chunksize, &sn, zero, commit, true);
|
||||
if (chunk != NULL) {
|
||||
if (arena_chunk_register(tsdn, arena, chunk, *zero)) {
|
||||
if (arena_chunk_register(tsdn, arena, chunk, sn, *zero)) {
|
||||
chunk_dalloc_cache(tsdn, arena, &chunk_hooks, chunk,
|
||||
chunksize, true);
|
||||
chunksize, sn, true);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
@ -621,6 +664,8 @@ arena_chunk_init_hard(tsdn_t *tsdn, arena_t *arena)
|
||||
if (chunk == NULL)
|
||||
return (NULL);
|
||||
|
||||
chunk->hugepage = true;
|
||||
|
||||
/*
|
||||
* Initialize the map to contain one maximal free untouched run. Mark
|
||||
* the pages as zeroed if arena_chunk_alloc_internal() returned a zeroed
|
||||
@ -684,11 +729,14 @@ arena_chunk_alloc(tsdn_t *tsdn, arena_t *arena)
|
||||
static void
|
||||
arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk)
|
||||
{
|
||||
size_t sn, hugepage;
|
||||
bool committed;
|
||||
chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER;
|
||||
|
||||
chunk_deregister(chunk, &chunk->node);
|
||||
|
||||
sn = extent_node_sn_get(&chunk->node);
|
||||
hugepage = chunk->hugepage;
|
||||
committed = (arena_mapbits_decommitted_get(chunk, map_bias) == 0);
|
||||
if (!committed) {
|
||||
/*
|
||||
@ -701,9 +749,17 @@ arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk)
|
||||
chunk_hooks.decommit(chunk, chunksize, 0, map_bias << LG_PAGE,
|
||||
arena->ind);
|
||||
}
|
||||
if (!hugepage) {
|
||||
/*
|
||||
* Convert chunk back to the default state, so that all
|
||||
* subsequent chunk allocations start out with chunks that can
|
||||
* be backed by transparent huge pages.
|
||||
*/
|
||||
pages_huge(chunk, chunksize);
|
||||
}
|
||||
|
||||
chunk_dalloc_cache(tsdn, arena, &chunk_hooks, (void *)chunk, chunksize,
|
||||
committed);
|
||||
sn, committed);
|
||||
|
||||
if (config_stats) {
|
||||
arena->stats.mapped -= chunksize;
|
||||
@ -859,14 +915,14 @@ arena_node_dalloc(tsdn_t *tsdn, arena_t *arena, extent_node_t *node)
|
||||
|
||||
static void *
|
||||
arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena,
|
||||
chunk_hooks_t *chunk_hooks, size_t usize, size_t alignment, bool *zero,
|
||||
size_t csize)
|
||||
chunk_hooks_t *chunk_hooks, size_t usize, size_t alignment, size_t *sn,
|
||||
bool *zero, size_t csize)
|
||||
{
|
||||
void *ret;
|
||||
bool commit = true;
|
||||
|
||||
ret = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, csize,
|
||||
alignment, zero, &commit);
|
||||
alignment, sn, zero, &commit);
|
||||
if (ret == NULL) {
|
||||
/* Revert optimistic stats updates. */
|
||||
malloc_mutex_lock(tsdn, &arena->lock);
|
||||
@ -883,7 +939,7 @@ arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena,
|
||||
|
||||
void *
|
||||
arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
||||
size_t alignment, bool *zero)
|
||||
size_t alignment, size_t *sn, bool *zero)
|
||||
{
|
||||
void *ret;
|
||||
chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER;
|
||||
@ -900,18 +956,19 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
||||
arena_nactive_add(arena, usize >> LG_PAGE);
|
||||
|
||||
ret = chunk_alloc_cache(tsdn, arena, &chunk_hooks, NULL, csize,
|
||||
alignment, zero, &commit, true);
|
||||
alignment, sn, zero, &commit, true);
|
||||
malloc_mutex_unlock(tsdn, &arena->lock);
|
||||
if (ret == NULL) {
|
||||
ret = arena_chunk_alloc_huge_hard(tsdn, arena, &chunk_hooks,
|
||||
usize, alignment, zero, csize);
|
||||
usize, alignment, sn, zero, csize);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, void *chunk, size_t usize)
|
||||
arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, void *chunk, size_t usize,
|
||||
size_t sn)
|
||||
{
|
||||
chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER;
|
||||
size_t csize;
|
||||
@ -924,7 +981,7 @@ arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, void *chunk, size_t usize)
|
||||
}
|
||||
arena_nactive_sub(arena, usize >> LG_PAGE);
|
||||
|
||||
chunk_dalloc_cache(tsdn, arena, &chunk_hooks, chunk, csize, true);
|
||||
chunk_dalloc_cache(tsdn, arena, &chunk_hooks, chunk, csize, sn, true);
|
||||
malloc_mutex_unlock(tsdn, &arena->lock);
|
||||
}
|
||||
|
||||
@ -948,7 +1005,7 @@ arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena, void *chunk,
|
||||
|
||||
void
|
||||
arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, void *chunk,
|
||||
size_t oldsize, size_t usize)
|
||||
size_t oldsize, size_t usize, size_t sn)
|
||||
{
|
||||
size_t udiff = oldsize - usize;
|
||||
size_t cdiff = CHUNK_CEILING(oldsize) - CHUNK_CEILING(usize);
|
||||
@ -967,7 +1024,7 @@ arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, void *chunk,
|
||||
CHUNK_CEILING(usize));
|
||||
|
||||
chunk_dalloc_cache(tsdn, arena, &chunk_hooks, nchunk, cdiff,
|
||||
true);
|
||||
sn, true);
|
||||
}
|
||||
malloc_mutex_unlock(tsdn, &arena->lock);
|
||||
}
|
||||
@ -975,13 +1032,13 @@ arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, void *chunk,
|
||||
static bool
|
||||
arena_chunk_ralloc_huge_expand_hard(tsdn_t *tsdn, arena_t *arena,
|
||||
chunk_hooks_t *chunk_hooks, void *chunk, size_t oldsize, size_t usize,
|
||||
bool *zero, void *nchunk, size_t udiff, size_t cdiff)
|
||||
size_t *sn, bool *zero, void *nchunk, size_t udiff, size_t cdiff)
|
||||
{
|
||||
bool err;
|
||||
bool commit = true;
|
||||
|
||||
err = (chunk_alloc_wrapper(tsdn, arena, chunk_hooks, nchunk, cdiff,
|
||||
chunksize, zero, &commit) == NULL);
|
||||
chunksize, sn, zero, &commit) == NULL);
|
||||
if (err) {
|
||||
/* Revert optimistic stats updates. */
|
||||
malloc_mutex_lock(tsdn, &arena->lock);
|
||||
@ -995,7 +1052,7 @@ arena_chunk_ralloc_huge_expand_hard(tsdn_t *tsdn, arena_t *arena,
|
||||
} else if (chunk_hooks->merge(chunk, CHUNK_CEILING(oldsize), nchunk,
|
||||
cdiff, true, arena->ind)) {
|
||||
chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, nchunk, cdiff,
|
||||
*zero, true);
|
||||
*sn, *zero, true);
|
||||
err = true;
|
||||
}
|
||||
return (err);
|
||||
@ -1010,6 +1067,7 @@ arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, void *chunk,
|
||||
void *nchunk = (void *)((uintptr_t)chunk + CHUNK_CEILING(oldsize));
|
||||
size_t udiff = usize - oldsize;
|
||||
size_t cdiff = CHUNK_CEILING(usize) - CHUNK_CEILING(oldsize);
|
||||
size_t sn;
|
||||
bool commit = true;
|
||||
|
||||
malloc_mutex_lock(tsdn, &arena->lock);
|
||||
@ -1022,16 +1080,16 @@ arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, void *chunk,
|
||||
arena_nactive_add(arena, udiff >> LG_PAGE);
|
||||
|
||||
err = (chunk_alloc_cache(tsdn, arena, &chunk_hooks, nchunk, cdiff,
|
||||
chunksize, zero, &commit, true) == NULL);
|
||||
chunksize, &sn, zero, &commit, true) == NULL);
|
||||
malloc_mutex_unlock(tsdn, &arena->lock);
|
||||
if (err) {
|
||||
err = arena_chunk_ralloc_huge_expand_hard(tsdn, arena,
|
||||
&chunk_hooks, chunk, oldsize, usize, zero, nchunk, udiff,
|
||||
cdiff);
|
||||
&chunk_hooks, chunk, oldsize, usize, &sn, zero, nchunk,
|
||||
udiff, cdiff);
|
||||
} else if (chunk_hooks.merge(chunk, CHUNK_CEILING(oldsize), nchunk,
|
||||
cdiff, true, arena->ind)) {
|
||||
chunk_dalloc_wrapper(tsdn, arena, &chunk_hooks, nchunk, cdiff,
|
||||
*zero, true);
|
||||
sn, *zero, true);
|
||||
err = true;
|
||||
}
|
||||
|
||||
@ -1519,6 +1577,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
|
||||
if (rdelm == &chunkselm->rd) {
|
||||
extent_node_t *chunkselm_next;
|
||||
size_t sn;
|
||||
bool zero, commit;
|
||||
UNUSED void *chunk;
|
||||
|
||||
@ -1536,8 +1595,8 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
commit = false;
|
||||
chunk = chunk_alloc_cache(tsdn, arena, chunk_hooks,
|
||||
extent_node_addr_get(chunkselm),
|
||||
extent_node_size_get(chunkselm), chunksize, &zero,
|
||||
&commit, false);
|
||||
extent_node_size_get(chunkselm), chunksize, &sn,
|
||||
&zero, &commit, false);
|
||||
assert(chunk == extent_node_addr_get(chunkselm));
|
||||
assert(zero == extent_node_zeroed_get(chunkselm));
|
||||
extent_node_dirty_insert(chunkselm, purge_runs_sentinel,
|
||||
@ -1634,6 +1693,17 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
run_size = arena_mapbits_large_size_get(chunk, pageind);
|
||||
npages = run_size >> LG_PAGE;
|
||||
|
||||
/*
|
||||
* If this is the first run purged within chunk, mark
|
||||
* the chunk as non-huge. This will prevent all use of
|
||||
* transparent huge pages for this chunk until the chunk
|
||||
* as a whole is deallocated.
|
||||
*/
|
||||
if (chunk->hugepage) {
|
||||
pages_nohuge(chunk, chunksize);
|
||||
chunk->hugepage = false;
|
||||
}
|
||||
|
||||
assert(pageind + npages <= chunk_npages);
|
||||
assert(!arena_mapbits_decommitted_get(chunk, pageind));
|
||||
assert(!arena_mapbits_decommitted_get(chunk,
|
||||
@ -1703,13 +1773,14 @@ arena_unstash_purged(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
cc_link);
|
||||
void *addr = extent_node_addr_get(chunkselm);
|
||||
size_t size = extent_node_size_get(chunkselm);
|
||||
size_t sn = extent_node_sn_get(chunkselm);
|
||||
bool zeroed = extent_node_zeroed_get(chunkselm);
|
||||
bool committed = extent_node_committed_get(chunkselm);
|
||||
extent_node_dirty_remove(chunkselm);
|
||||
arena_node_dalloc(tsdn, arena, chunkselm);
|
||||
chunkselm = chunkselm_next;
|
||||
chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, addr,
|
||||
size, zeroed, committed);
|
||||
size, sn, zeroed, committed);
|
||||
} else {
|
||||
arena_chunk_t *chunk =
|
||||
(arena_chunk_t *)CHUNK_ADDR2BASE(rdelm);
|
||||
@ -2315,7 +2386,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin)
|
||||
arena_dalloc_bin_run(tsdn, arena, chunk, run,
|
||||
bin);
|
||||
} else
|
||||
arena_bin_lower_run(arena, chunk, run, bin);
|
||||
arena_bin_lower_run(arena, run, bin);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
@ -2820,16 +2891,18 @@ arena_dalloc_bin_run(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk,
|
||||
}
|
||||
|
||||
static void
|
||||
arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
|
||||
arena_bin_t *bin)
|
||||
arena_bin_lower_run(arena_t *arena, arena_run_t *run, arena_bin_t *bin)
|
||||
{
|
||||
|
||||
/*
|
||||
* Make sure that if bin->runcur is non-NULL, it refers to the lowest
|
||||
* non-full run. It is okay to NULL runcur out rather than proactively
|
||||
* keeping it pointing at the lowest non-full run.
|
||||
* Make sure that if bin->runcur is non-NULL, it refers to the
|
||||
* oldest/lowest non-full run. It is okay to NULL runcur out rather
|
||||
* than proactively keeping it pointing at the oldest/lowest non-full
|
||||
* run.
|
||||
*/
|
||||
if ((uintptr_t)run < (uintptr_t)bin->runcur) {
|
||||
if (bin->runcur != NULL &&
|
||||
arena_snad_comp(arena_run_to_miscelm(bin->runcur),
|
||||
arena_run_to_miscelm(run)) > 0) {
|
||||
/* Switch runcur. */
|
||||
if (bin->runcur->nfree > 0)
|
||||
arena_bin_runs_insert(bin, bin->runcur);
|
||||
@ -2865,7 +2938,7 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk,
|
||||
arena_dissociate_bin_run(chunk, run, bin);
|
||||
arena_dalloc_bin_run(tsdn, arena, chunk, run, bin);
|
||||
} else if (run->nfree == 1 && run != bin->runcur)
|
||||
arena_bin_lower_run(arena, chunk, run, bin);
|
||||
arena_bin_lower_run(arena, run, bin);
|
||||
|
||||
if (config_stats) {
|
||||
bin->stats.ndalloc++;
|
||||
@ -3452,6 +3525,13 @@ arena_nthreads_dec(arena_t *arena, bool internal)
|
||||
atomic_sub_u(&arena->nthreads[internal], 1);
|
||||
}
|
||||
|
||||
size_t
|
||||
arena_extent_sn_next(arena_t *arena)
|
||||
{
|
||||
|
||||
return (atomic_add_z(&arena->extent_sn_next, 1) - 1);
|
||||
}
|
||||
|
||||
arena_t *
|
||||
arena_new(tsdn_t *tsdn, unsigned ind)
|
||||
{
|
||||
@ -3511,6 +3591,8 @@ arena_new(tsdn_t *tsdn, unsigned ind)
|
||||
|
||||
ql_new(&arena->achunks);
|
||||
|
||||
arena->extent_sn_next = 0;
|
||||
|
||||
arena->spare = NULL;
|
||||
|
||||
arena->lg_dirty_mult = arena_lg_dirty_mult_default_get();
|
||||
@ -3532,9 +3614,9 @@ arena_new(tsdn_t *tsdn, unsigned ind)
|
||||
WITNESS_RANK_ARENA_HUGE))
|
||||
return (NULL);
|
||||
|
||||
extent_tree_szad_new(&arena->chunks_szad_cached);
|
||||
extent_tree_szsnad_new(&arena->chunks_szsnad_cached);
|
||||
extent_tree_ad_new(&arena->chunks_ad_cached);
|
||||
extent_tree_szad_new(&arena->chunks_szad_retained);
|
||||
extent_tree_szsnad_new(&arena->chunks_szsnad_retained);
|
||||
extent_tree_ad_new(&arena->chunks_ad_retained);
|
||||
if (malloc_mutex_init(&arena->chunks_mtx, "arena_chunks",
|
||||
WITNESS_RANK_ARENA_CHUNKS))
|
||||
|
@ -5,7 +5,8 @@
|
||||
/* Data. */
|
||||
|
||||
static malloc_mutex_t base_mtx;
|
||||
static extent_tree_t base_avail_szad;
|
||||
static size_t base_extent_sn_next;
|
||||
static extent_tree_t base_avail_szsnad;
|
||||
static extent_node_t *base_nodes;
|
||||
static size_t base_allocated;
|
||||
static size_t base_resident;
|
||||
@ -39,6 +40,14 @@ base_node_dalloc(tsdn_t *tsdn, extent_node_t *node)
|
||||
base_nodes = node;
|
||||
}
|
||||
|
||||
static void
|
||||
base_extent_node_init(extent_node_t *node, void *addr, size_t size)
|
||||
{
|
||||
size_t sn = atomic_add_z(&base_extent_sn_next, 1) - 1;
|
||||
|
||||
extent_node_init(node, NULL, addr, size, sn, true, true);
|
||||
}
|
||||
|
||||
static extent_node_t *
|
||||
base_chunk_alloc(tsdn_t *tsdn, size_t minsize)
|
||||
{
|
||||
@ -68,7 +77,7 @@ base_chunk_alloc(tsdn_t *tsdn, size_t minsize)
|
||||
base_resident += PAGE_CEILING(nsize);
|
||||
}
|
||||
}
|
||||
extent_node_init(node, NULL, addr, csize, true, true);
|
||||
base_extent_node_init(node, addr, csize);
|
||||
return (node);
|
||||
}
|
||||
|
||||
@ -92,12 +101,12 @@ base_alloc(tsdn_t *tsdn, size_t size)
|
||||
csize = CACHELINE_CEILING(size);
|
||||
|
||||
usize = s2u(csize);
|
||||
extent_node_init(&key, NULL, NULL, usize, false, false);
|
||||
extent_node_init(&key, NULL, NULL, usize, 0, false, false);
|
||||
malloc_mutex_lock(tsdn, &base_mtx);
|
||||
node = extent_tree_szad_nsearch(&base_avail_szad, &key);
|
||||
node = extent_tree_szsnad_nsearch(&base_avail_szsnad, &key);
|
||||
if (node != NULL) {
|
||||
/* Use existing space. */
|
||||
extent_tree_szad_remove(&base_avail_szad, node);
|
||||
extent_tree_szsnad_remove(&base_avail_szsnad, node);
|
||||
} else {
|
||||
/* Try to allocate more space. */
|
||||
node = base_chunk_alloc(tsdn, csize);
|
||||
@ -111,7 +120,7 @@ base_alloc(tsdn_t *tsdn, size_t size)
|
||||
if (extent_node_size_get(node) > csize) {
|
||||
extent_node_addr_set(node, (void *)((uintptr_t)ret + csize));
|
||||
extent_node_size_set(node, extent_node_size_get(node) - csize);
|
||||
extent_tree_szad_insert(&base_avail_szad, node);
|
||||
extent_tree_szsnad_insert(&base_avail_szsnad, node);
|
||||
} else
|
||||
base_node_dalloc(tsdn, node);
|
||||
if (config_stats) {
|
||||
@ -149,7 +158,8 @@ base_boot(void)
|
||||
|
||||
if (malloc_mutex_init(&base_mtx, "base", WITNESS_RANK_BASE))
|
||||
return (true);
|
||||
extent_tree_szad_new(&base_avail_szad);
|
||||
base_extent_sn_next = 0;
|
||||
extent_tree_szsnad_new(&base_avail_szsnad);
|
||||
base_nodes = NULL;
|
||||
|
||||
return (false);
|
||||
|
@ -50,9 +50,9 @@ const chunk_hooks_t chunk_hooks_default = {
|
||||
*/
|
||||
|
||||
static void chunk_record(tsdn_t *tsdn, arena_t *arena,
|
||||
chunk_hooks_t *chunk_hooks, extent_tree_t *chunks_szad,
|
||||
extent_tree_t *chunks_ad, bool cache, void *chunk, size_t size, bool zeroed,
|
||||
bool committed);
|
||||
chunk_hooks_t *chunk_hooks, extent_tree_t *chunks_szsnad,
|
||||
extent_tree_t *chunks_ad, bool cache, void *chunk, size_t size, size_t sn,
|
||||
bool zeroed, bool committed);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@ -183,33 +183,35 @@ chunk_deregister(const void *chunk, const extent_node_t *node)
|
||||
}
|
||||
|
||||
/*
|
||||
* Do first-best-fit chunk selection, i.e. select the lowest chunk that best
|
||||
* fits.
|
||||
* Do first-best-fit chunk selection, i.e. select the oldest/lowest chunk that
|
||||
* best fits.
|
||||
*/
|
||||
static extent_node_t *
|
||||
chunk_first_best_fit(arena_t *arena, extent_tree_t *chunks_szad,
|
||||
extent_tree_t *chunks_ad, size_t size)
|
||||
chunk_first_best_fit(arena_t *arena, extent_tree_t *chunks_szsnad, size_t size)
|
||||
{
|
||||
extent_node_t key;
|
||||
|
||||
assert(size == CHUNK_CEILING(size));
|
||||
|
||||
extent_node_init(&key, arena, NULL, size, false, false);
|
||||
return (extent_tree_szad_nsearch(chunks_szad, &key));
|
||||
extent_node_init(&key, arena, NULL, size, 0, false, false);
|
||||
return (extent_tree_szsnad_nsearch(chunks_szsnad, &key));
|
||||
}
|
||||
|
||||
static void *
|
||||
chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, bool cache,
|
||||
void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit,
|
||||
bool dalloc_node)
|
||||
extent_tree_t *chunks_szsnad, extent_tree_t *chunks_ad, bool cache,
|
||||
void *new_addr, size_t size, size_t alignment, size_t *sn, bool *zero,
|
||||
bool *commit, bool dalloc_node)
|
||||
{
|
||||
void *ret;
|
||||
extent_node_t *node;
|
||||
size_t alloc_size, leadsize, trailsize;
|
||||
bool zeroed, committed;
|
||||
|
||||
assert(CHUNK_CEILING(size) == size);
|
||||
assert(alignment > 0);
|
||||
assert(new_addr == NULL || alignment == chunksize);
|
||||
assert(CHUNK_ADDR2BASE(new_addr) == new_addr);
|
||||
/*
|
||||
* Cached chunks use the node linkage embedded in their headers, in
|
||||
* which case dalloc_node is true, and new_addr is non-NULL because
|
||||
@ -217,7 +219,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
*/
|
||||
assert(dalloc_node || new_addr != NULL);
|
||||
|
||||
alloc_size = CHUNK_CEILING(s2u(size + alignment - chunksize));
|
||||
alloc_size = size + CHUNK_CEILING(alignment) - chunksize;
|
||||
/* Beware size_t wrap-around. */
|
||||
if (alloc_size < size)
|
||||
return (NULL);
|
||||
@ -225,12 +227,11 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks);
|
||||
if (new_addr != NULL) {
|
||||
extent_node_t key;
|
||||
extent_node_init(&key, arena, new_addr, alloc_size, false,
|
||||
extent_node_init(&key, arena, new_addr, alloc_size, 0, false,
|
||||
false);
|
||||
node = extent_tree_ad_search(chunks_ad, &key);
|
||||
} else {
|
||||
node = chunk_first_best_fit(arena, chunks_szad, chunks_ad,
|
||||
alloc_size);
|
||||
node = chunk_first_best_fit(arena, chunks_szsnad, alloc_size);
|
||||
}
|
||||
if (node == NULL || (new_addr != NULL && extent_node_size_get(node) <
|
||||
size)) {
|
||||
@ -243,6 +244,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
assert(extent_node_size_get(node) >= leadsize + size);
|
||||
trailsize = extent_node_size_get(node) - leadsize - size;
|
||||
ret = (void *)((uintptr_t)extent_node_addr_get(node) + leadsize);
|
||||
*sn = extent_node_sn_get(node);
|
||||
zeroed = extent_node_zeroed_get(node);
|
||||
if (zeroed)
|
||||
*zero = true;
|
||||
@ -257,13 +259,13 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
return (NULL);
|
||||
}
|
||||
/* Remove node from the tree. */
|
||||
extent_tree_szad_remove(chunks_szad, node);
|
||||
extent_tree_szsnad_remove(chunks_szsnad, node);
|
||||
extent_tree_ad_remove(chunks_ad, node);
|
||||
arena_chunk_cache_maybe_remove(arena, node, cache);
|
||||
if (leadsize != 0) {
|
||||
/* Insert the leading space as a smaller chunk. */
|
||||
extent_node_size_set(node, leadsize);
|
||||
extent_tree_szad_insert(chunks_szad, node);
|
||||
extent_tree_szsnad_insert(chunks_szsnad, node);
|
||||
extent_tree_ad_insert(chunks_ad, node);
|
||||
arena_chunk_cache_maybe_insert(arena, node, cache);
|
||||
node = NULL;
|
||||
@ -275,9 +277,9 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
if (dalloc_node && node != NULL)
|
||||
arena_node_dalloc(tsdn, arena, node);
|
||||
malloc_mutex_unlock(tsdn, &arena->chunks_mtx);
|
||||
chunk_record(tsdn, arena, chunk_hooks, chunks_szad,
|
||||
chunks_ad, cache, ret, size + trailsize, zeroed,
|
||||
committed);
|
||||
chunk_record(tsdn, arena, chunk_hooks, chunks_szsnad,
|
||||
chunks_ad, cache, ret, size + trailsize, *sn,
|
||||
zeroed, committed);
|
||||
return (NULL);
|
||||
}
|
||||
/* Insert the trailing space as a smaller chunk. */
|
||||
@ -286,22 +288,22 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
if (node == NULL) {
|
||||
malloc_mutex_unlock(tsdn, &arena->chunks_mtx);
|
||||
chunk_record(tsdn, arena, chunk_hooks,
|
||||
chunks_szad, chunks_ad, cache, ret, size +
|
||||
trailsize, zeroed, committed);
|
||||
chunks_szsnad, chunks_ad, cache, ret, size
|
||||
+ trailsize, *sn, zeroed, committed);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
extent_node_init(node, arena, (void *)((uintptr_t)(ret) + size),
|
||||
trailsize, zeroed, committed);
|
||||
extent_tree_szad_insert(chunks_szad, node);
|
||||
trailsize, *sn, zeroed, committed);
|
||||
extent_tree_szsnad_insert(chunks_szsnad, node);
|
||||
extent_tree_ad_insert(chunks_ad, node);
|
||||
arena_chunk_cache_maybe_insert(arena, node, cache);
|
||||
node = NULL;
|
||||
}
|
||||
if (!committed && chunk_hooks->commit(ret, size, 0, size, arena->ind)) {
|
||||
malloc_mutex_unlock(tsdn, &arena->chunks_mtx);
|
||||
chunk_record(tsdn, arena, chunk_hooks, chunks_szad, chunks_ad,
|
||||
cache, ret, size, zeroed, committed);
|
||||
chunk_record(tsdn, arena, chunk_hooks, chunks_szsnad, chunks_ad,
|
||||
cache, ret, size, *sn, zeroed, committed);
|
||||
return (NULL);
|
||||
}
|
||||
malloc_mutex_unlock(tsdn, &arena->chunks_mtx);
|
||||
@ -385,8 +387,8 @@ chunk_alloc_base(size_t size)
|
||||
|
||||
void *
|
||||
chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit,
|
||||
bool dalloc_node)
|
||||
void *new_addr, size_t size, size_t alignment, size_t *sn, bool *zero,
|
||||
bool *commit, bool dalloc_node)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
@ -396,8 +398,8 @@ chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
assert((alignment & chunksize_mask) == 0);
|
||||
|
||||
ret = chunk_recycle(tsdn, arena, chunk_hooks,
|
||||
&arena->chunks_szad_cached, &arena->chunks_ad_cached, true,
|
||||
new_addr, size, alignment, zero, commit, dalloc_node);
|
||||
&arena->chunks_szsnad_cached, &arena->chunks_ad_cached, true,
|
||||
new_addr, size, alignment, sn, zero, commit, dalloc_node);
|
||||
if (ret == NULL)
|
||||
return (NULL);
|
||||
if (config_valgrind)
|
||||
@ -451,7 +453,8 @@ chunk_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero,
|
||||
|
||||
static void *
|
||||
chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit)
|
||||
void *new_addr, size_t size, size_t alignment, size_t *sn, bool *zero,
|
||||
bool *commit)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
@ -461,8 +464,8 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
assert((alignment & chunksize_mask) == 0);
|
||||
|
||||
ret = chunk_recycle(tsdn, arena, chunk_hooks,
|
||||
&arena->chunks_szad_retained, &arena->chunks_ad_retained, false,
|
||||
new_addr, size, alignment, zero, commit, true);
|
||||
&arena->chunks_szsnad_retained, &arena->chunks_ad_retained, false,
|
||||
new_addr, size, alignment, sn, zero, commit, true);
|
||||
|
||||
if (config_stats && ret != NULL)
|
||||
arena->stats.retained -= size;
|
||||
@ -472,14 +475,15 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
|
||||
void *
|
||||
chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit)
|
||||
void *new_addr, size_t size, size_t alignment, size_t *sn, bool *zero,
|
||||
bool *commit)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks);
|
||||
|
||||
ret = chunk_alloc_retained(tsdn, arena, chunk_hooks, new_addr, size,
|
||||
alignment, zero, commit);
|
||||
alignment, sn, zero, commit);
|
||||
if (ret == NULL) {
|
||||
if (chunk_hooks->alloc == chunk_alloc_default) {
|
||||
/* Call directly to propagate tsdn. */
|
||||
@ -493,6 +497,8 @@ chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
if (ret == NULL)
|
||||
return (NULL);
|
||||
|
||||
*sn = arena_extent_sn_next(arena);
|
||||
|
||||
if (config_valgrind && chunk_hooks->alloc !=
|
||||
chunk_alloc_default)
|
||||
JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, chunksize);
|
||||
@ -503,8 +509,8 @@ chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
|
||||
static void
|
||||
chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, bool cache,
|
||||
void *chunk, size_t size, bool zeroed, bool committed)
|
||||
extent_tree_t *chunks_szsnad, extent_tree_t *chunks_ad, bool cache,
|
||||
void *chunk, size_t size, size_t sn, bool zeroed, bool committed)
|
||||
{
|
||||
bool unzeroed;
|
||||
extent_node_t *node, *prev;
|
||||
@ -516,7 +522,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
|
||||
malloc_mutex_lock(tsdn, &arena->chunks_mtx);
|
||||
chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks);
|
||||
extent_node_init(&key, arena, (void *)((uintptr_t)chunk + size), 0,
|
||||
extent_node_init(&key, arena, (void *)((uintptr_t)chunk + size), 0, 0,
|
||||
false, false);
|
||||
node = extent_tree_ad_nsearch(chunks_ad, &key);
|
||||
/* Try to coalesce forward. */
|
||||
@ -528,15 +534,17 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
/*
|
||||
* Coalesce chunk with the following address range. This does
|
||||
* not change the position within chunks_ad, so only
|
||||
* remove/insert from/into chunks_szad.
|
||||
* remove/insert from/into chunks_szsnad.
|
||||
*/
|
||||
extent_tree_szad_remove(chunks_szad, node);
|
||||
extent_tree_szsnad_remove(chunks_szsnad, node);
|
||||
arena_chunk_cache_maybe_remove(arena, node, cache);
|
||||
extent_node_addr_set(node, chunk);
|
||||
extent_node_size_set(node, size + extent_node_size_get(node));
|
||||
if (sn < extent_node_sn_get(node))
|
||||
extent_node_sn_set(node, sn);
|
||||
extent_node_zeroed_set(node, extent_node_zeroed_get(node) &&
|
||||
!unzeroed);
|
||||
extent_tree_szad_insert(chunks_szad, node);
|
||||
extent_tree_szsnad_insert(chunks_szsnad, node);
|
||||
arena_chunk_cache_maybe_insert(arena, node, cache);
|
||||
} else {
|
||||
/* Coalescing forward failed, so insert a new node. */
|
||||
@ -554,10 +562,10 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
}
|
||||
goto label_return;
|
||||
}
|
||||
extent_node_init(node, arena, chunk, size, !unzeroed,
|
||||
extent_node_init(node, arena, chunk, size, sn, !unzeroed,
|
||||
committed);
|
||||
extent_tree_ad_insert(chunks_ad, node);
|
||||
extent_tree_szad_insert(chunks_szad, node);
|
||||
extent_tree_szsnad_insert(chunks_szsnad, node);
|
||||
arena_chunk_cache_maybe_insert(arena, node, cache);
|
||||
}
|
||||
|
||||
@ -571,19 +579,21 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
/*
|
||||
* Coalesce chunk with the previous address range. This does
|
||||
* not change the position within chunks_ad, so only
|
||||
* remove/insert node from/into chunks_szad.
|
||||
* remove/insert node from/into chunks_szsnad.
|
||||
*/
|
||||
extent_tree_szad_remove(chunks_szad, prev);
|
||||
extent_tree_szsnad_remove(chunks_szsnad, prev);
|
||||
extent_tree_ad_remove(chunks_ad, prev);
|
||||
arena_chunk_cache_maybe_remove(arena, prev, cache);
|
||||
extent_tree_szad_remove(chunks_szad, node);
|
||||
extent_tree_szsnad_remove(chunks_szsnad, node);
|
||||
arena_chunk_cache_maybe_remove(arena, node, cache);
|
||||
extent_node_addr_set(node, extent_node_addr_get(prev));
|
||||
extent_node_size_set(node, extent_node_size_get(prev) +
|
||||
extent_node_size_get(node));
|
||||
if (extent_node_sn_get(prev) < extent_node_sn_get(node))
|
||||
extent_node_sn_set(node, extent_node_sn_get(prev));
|
||||
extent_node_zeroed_set(node, extent_node_zeroed_get(prev) &&
|
||||
extent_node_zeroed_get(node));
|
||||
extent_tree_szad_insert(chunks_szad, node);
|
||||
extent_tree_szsnad_insert(chunks_szsnad, node);
|
||||
arena_chunk_cache_maybe_insert(arena, node, cache);
|
||||
|
||||
arena_node_dalloc(tsdn, arena, prev);
|
||||
@ -595,7 +605,7 @@ label_return:
|
||||
|
||||
void
|
||||
chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
void *chunk, size_t size, bool committed)
|
||||
void *chunk, size_t size, size_t sn, bool committed)
|
||||
{
|
||||
|
||||
assert(chunk != NULL);
|
||||
@ -603,8 +613,9 @@ chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
assert(size != 0);
|
||||
assert((size & chunksize_mask) == 0);
|
||||
|
||||
chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szad_cached,
|
||||
&arena->chunks_ad_cached, true, chunk, size, false, committed);
|
||||
chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szsnad_cached,
|
||||
&arena->chunks_ad_cached, true, chunk, size, sn, false,
|
||||
committed);
|
||||
arena_maybe_purge(tsdn, arena);
|
||||
}
|
||||
|
||||
@ -627,7 +638,7 @@ chunk_dalloc_default(void *chunk, size_t size, bool committed,
|
||||
|
||||
void
|
||||
chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
void *chunk, size_t size, bool zeroed, bool committed)
|
||||
void *chunk, size_t size, size_t sn, bool zeroed, bool committed)
|
||||
{
|
||||
bool err;
|
||||
|
||||
@ -653,8 +664,9 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
}
|
||||
zeroed = !committed || !chunk_hooks->purge(chunk, size, 0, size,
|
||||
arena->ind);
|
||||
chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szad_retained,
|
||||
&arena->chunks_ad_retained, false, chunk, size, zeroed, committed);
|
||||
chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szsnad_retained,
|
||||
&arena->chunks_ad_retained, false, chunk, size, sn, zeroed,
|
||||
committed);
|
||||
|
||||
if (config_stats)
|
||||
arena->stats.retained += size;
|
||||
|
@ -162,7 +162,8 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size,
|
||||
CHUNK_HOOKS_INITIALIZER;
|
||||
chunk_dalloc_wrapper(tsdn, arena,
|
||||
&chunk_hooks, cpad, cpad_size,
|
||||
false, true);
|
||||
arena_extent_sn_next(arena), false,
|
||||
true);
|
||||
}
|
||||
if (*zero) {
|
||||
JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(
|
||||
|
@ -3,42 +3,45 @@
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/*
|
||||
* Round down to the nearest chunk size that can actually be requested during
|
||||
* normal huge allocation.
|
||||
*/
|
||||
JEMALLOC_INLINE_C size_t
|
||||
extent_quantize(size_t size)
|
||||
{
|
||||
size_t ret;
|
||||
szind_t ind;
|
||||
|
||||
/*
|
||||
* Round down to the nearest chunk size that can actually be requested
|
||||
* during normal huge allocation.
|
||||
*/
|
||||
return (index2size(size2index(size + 1) - 1));
|
||||
assert(size > 0);
|
||||
|
||||
ind = size2index(size + 1);
|
||||
if (ind == 0) {
|
||||
/* Avoid underflow. */
|
||||
return (index2size(0));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE_C int
|
||||
extent_szad_comp(const extent_node_t *a, const extent_node_t *b)
|
||||
{
|
||||
int ret;
|
||||
size_t a_qsize = extent_quantize(extent_node_size_get(a));
|
||||
size_t b_qsize = extent_quantize(extent_node_size_get(b));
|
||||
|
||||
/*
|
||||
* Compare based on quantized size rather than size, in order to sort
|
||||
* equally useful extents only by address.
|
||||
*/
|
||||
ret = (a_qsize > b_qsize) - (a_qsize < b_qsize);
|
||||
if (ret == 0) {
|
||||
uintptr_t a_addr = (uintptr_t)extent_node_addr_get(a);
|
||||
uintptr_t b_addr = (uintptr_t)extent_node_addr_get(b);
|
||||
|
||||
ret = (a_addr > b_addr) - (a_addr < b_addr);
|
||||
}
|
||||
|
||||
ret = index2size(ind - 1);
|
||||
assert(ret <= size);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Generate red-black tree functions. */
|
||||
rb_gen(, extent_tree_szad_, extent_tree_t, extent_node_t, szad_link,
|
||||
extent_szad_comp)
|
||||
JEMALLOC_INLINE_C int
|
||||
extent_sz_comp(const extent_node_t *a, const extent_node_t *b)
|
||||
{
|
||||
size_t a_qsize = extent_quantize(extent_node_size_get(a));
|
||||
size_t b_qsize = extent_quantize(extent_node_size_get(b));
|
||||
|
||||
return ((a_qsize > b_qsize) - (a_qsize < b_qsize));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE_C int
|
||||
extent_sn_comp(const extent_node_t *a, const extent_node_t *b)
|
||||
{
|
||||
size_t a_sn = extent_node_sn_get(a);
|
||||
size_t b_sn = extent_node_sn_get(b);
|
||||
|
||||
return ((a_sn > b_sn) - (a_sn < b_sn));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE_C int
|
||||
extent_ad_comp(const extent_node_t *a, const extent_node_t *b)
|
||||
@ -49,5 +52,26 @@ extent_ad_comp(const extent_node_t *a, const extent_node_t *b)
|
||||
return ((a_addr > b_addr) - (a_addr < b_addr));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE_C int
|
||||
extent_szsnad_comp(const extent_node_t *a, const extent_node_t *b)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = extent_sz_comp(a, b);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
ret = extent_sn_comp(a, b);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
ret = extent_ad_comp(a, b);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Generate red-black tree functions. */
|
||||
rb_gen(, extent_tree_szsnad_, extent_tree_t, extent_node_t, szsnad_link,
|
||||
extent_szsnad_comp)
|
||||
|
||||
/* Generate red-black tree functions. */
|
||||
rb_gen(, extent_tree_ad_, extent_tree_t, extent_node_t, ad_link, extent_ad_comp)
|
||||
|
@ -56,6 +56,7 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
||||
size_t ausize;
|
||||
arena_t *iarena;
|
||||
extent_node_t *node;
|
||||
size_t sn;
|
||||
bool is_zeroed;
|
||||
|
||||
/* Allocate one or more contiguous chunks for this request. */
|
||||
@ -68,7 +69,8 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
||||
assert(ausize >= chunksize);
|
||||
|
||||
/* Allocate an extent node with which to track the chunk. */
|
||||
iarena = (!tsdn_null(tsdn)) ? arena_ichoose(tsdn_tsd(tsdn), NULL) : a0get();
|
||||
iarena = (!tsdn_null(tsdn)) ? arena_ichoose(tsdn_tsd(tsdn), NULL) :
|
||||
a0get();
|
||||
node = ipallocztm(tsdn, CACHELINE_CEILING(sizeof(extent_node_t)),
|
||||
CACHELINE, false, NULL, true, iarena);
|
||||
if (node == NULL)
|
||||
@ -82,15 +84,15 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
||||
if (likely(!tsdn_null(tsdn)))
|
||||
arena = arena_choose(tsdn_tsd(tsdn), arena);
|
||||
if (unlikely(arena == NULL) || (ret = arena_chunk_alloc_huge(tsdn,
|
||||
arena, usize, alignment, &is_zeroed)) == NULL) {
|
||||
arena, usize, alignment, &sn, &is_zeroed)) == NULL) {
|
||||
idalloctm(tsdn, node, NULL, true, true);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
extent_node_init(node, arena, ret, usize, is_zeroed, true);
|
||||
extent_node_init(node, arena, ret, usize, sn, is_zeroed, true);
|
||||
|
||||
if (huge_node_set(tsdn, ret, node)) {
|
||||
arena_chunk_dalloc_huge(tsdn, arena, ret, usize);
|
||||
arena_chunk_dalloc_huge(tsdn, arena, ret, usize, sn);
|
||||
idalloctm(tsdn, node, NULL, true, true);
|
||||
return (NULL);
|
||||
}
|
||||
@ -245,7 +247,8 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, void *ptr, size_t oldsize,
|
||||
malloc_mutex_unlock(tsdn, &arena->huge_mtx);
|
||||
|
||||
/* Zap the excess chunks. */
|
||||
arena_chunk_ralloc_huge_shrink(tsdn, arena, ptr, oldsize, usize);
|
||||
arena_chunk_ralloc_huge_shrink(tsdn, arena, ptr, oldsize, usize,
|
||||
extent_node_sn_get(node));
|
||||
|
||||
return (false);
|
||||
}
|
||||
@ -407,7 +410,8 @@ huge_dalloc(tsdn_t *tsdn, void *ptr)
|
||||
huge_dalloc_junk(extent_node_addr_get(node),
|
||||
extent_node_size_get(node));
|
||||
arena_chunk_dalloc_huge(tsdn, extent_node_arena_get(node),
|
||||
extent_node_addr_get(node), extent_node_size_get(node));
|
||||
extent_node_addr_get(node), extent_node_size_get(node),
|
||||
extent_node_sn_get(node));
|
||||
idalloctm(tsdn, node, NULL, true, true);
|
||||
|
||||
arena_decay_tick(tsdn, arena);
|
||||
|
@ -1060,7 +1060,11 @@ malloc_conf_init(void)
|
||||
if (cont) \
|
||||
continue; \
|
||||
}
|
||||
#define CONF_HANDLE_T_U(t, o, n, min, max, clip) \
|
||||
#define CONF_MIN_no(um, min) false
|
||||
#define CONF_MIN_yes(um, min) ((um) < (min))
|
||||
#define CONF_MAX_no(um, max) false
|
||||
#define CONF_MAX_yes(um, max) ((um) > (max))
|
||||
#define CONF_HANDLE_T_U(t, o, n, min, max, check_min, check_max, clip) \
|
||||
if (CONF_MATCH(n)) { \
|
||||
uintmax_t um; \
|
||||
char *end; \
|
||||
@ -1073,15 +1077,19 @@ malloc_conf_init(void)
|
||||
"Invalid conf value", \
|
||||
k, klen, v, vlen); \
|
||||
} else if (clip) { \
|
||||
if ((min) != 0 && um < (min)) \
|
||||
if (CONF_MIN_##check_min(um, \
|
||||
(min))) \
|
||||
o = (t)(min); \
|
||||
else if (um > (max)) \
|
||||
else if (CONF_MAX_##check_max( \
|
||||
um, (max))) \
|
||||
o = (t)(max); \
|
||||
else \
|
||||
o = (t)um; \
|
||||
} else { \
|
||||
if (((min) != 0 && um < (min)) \
|
||||
|| um > (max)) { \
|
||||
if (CONF_MIN_##check_min(um, \
|
||||
(min)) || \
|
||||
CONF_MAX_##check_max(um, \
|
||||
(max))) { \
|
||||
malloc_conf_error( \
|
||||
"Out-of-range " \
|
||||
"conf value", \
|
||||
@ -1091,10 +1099,13 @@ malloc_conf_init(void)
|
||||
} \
|
||||
continue; \
|
||||
}
|
||||
#define CONF_HANDLE_UNSIGNED(o, n, min, max, clip) \
|
||||
CONF_HANDLE_T_U(unsigned, o, n, min, max, clip)
|
||||
#define CONF_HANDLE_SIZE_T(o, n, min, max, clip) \
|
||||
CONF_HANDLE_T_U(size_t, o, n, min, max, clip)
|
||||
#define CONF_HANDLE_UNSIGNED(o, n, min, max, check_min, check_max, \
|
||||
clip) \
|
||||
CONF_HANDLE_T_U(unsigned, o, n, min, max, \
|
||||
check_min, check_max, clip)
|
||||
#define CONF_HANDLE_SIZE_T(o, n, min, max, check_min, check_max, clip) \
|
||||
CONF_HANDLE_T_U(size_t, o, n, min, max, \
|
||||
check_min, check_max, clip)
|
||||
#define CONF_HANDLE_SSIZE_T(o, n, min, max) \
|
||||
if (CONF_MATCH(n)) { \
|
||||
long l; \
|
||||
@ -1137,7 +1148,7 @@ malloc_conf_init(void)
|
||||
*/
|
||||
CONF_HANDLE_SIZE_T(opt_lg_chunk, "lg_chunk", LG_PAGE +
|
||||
LG_SIZE_CLASS_GROUP + (config_fill ? 2 : 1),
|
||||
(sizeof(size_t) << 3) - 1, true)
|
||||
(sizeof(size_t) << 3) - 1, yes, yes, true)
|
||||
if (strncmp("dss", k, klen) == 0) {
|
||||
int i;
|
||||
bool match = false;
|
||||
@ -1163,7 +1174,7 @@ malloc_conf_init(void)
|
||||
continue;
|
||||
}
|
||||
CONF_HANDLE_UNSIGNED(opt_narenas, "narenas", 1,
|
||||
UINT_MAX, false)
|
||||
UINT_MAX, yes, no, false)
|
||||
if (strncmp("purge", k, klen) == 0) {
|
||||
int i;
|
||||
bool match = false;
|
||||
@ -1234,7 +1245,7 @@ malloc_conf_init(void)
|
||||
continue;
|
||||
}
|
||||
CONF_HANDLE_SIZE_T(opt_quarantine, "quarantine",
|
||||
0, SIZE_T_MAX, false)
|
||||
0, SIZE_T_MAX, no, no, false)
|
||||
CONF_HANDLE_BOOL(opt_redzone, "redzone", true)
|
||||
CONF_HANDLE_BOOL(opt_zero, "zero", true)
|
||||
}
|
||||
@ -1271,8 +1282,8 @@ malloc_conf_init(void)
|
||||
CONF_HANDLE_BOOL(opt_prof_thread_active_init,
|
||||
"prof_thread_active_init", true)
|
||||
CONF_HANDLE_SIZE_T(opt_lg_prof_sample,
|
||||
"lg_prof_sample", 0,
|
||||
(sizeof(uint64_t) << 3) - 1, true)
|
||||
"lg_prof_sample", 0, (sizeof(uint64_t) << 3)
|
||||
- 1, no, yes, true)
|
||||
CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum",
|
||||
true)
|
||||
CONF_HANDLE_SSIZE_T(opt_lg_prof_interval,
|
||||
@ -1288,7 +1299,14 @@ malloc_conf_init(void)
|
||||
malloc_conf_error("Invalid conf pair", k, klen, v,
|
||||
vlen);
|
||||
#undef CONF_MATCH
|
||||
#undef CONF_MATCH_VALUE
|
||||
#undef CONF_HANDLE_BOOL
|
||||
#undef CONF_MIN_no
|
||||
#undef CONF_MIN_yes
|
||||
#undef CONF_MAX_no
|
||||
#undef CONF_MAX_yes
|
||||
#undef CONF_HANDLE_T_U
|
||||
#undef CONF_HANDLE_UNSIGNED
|
||||
#undef CONF_HANDLE_SIZE_T
|
||||
#undef CONF_HANDLE_SSIZE_T
|
||||
#undef CONF_HANDLE_CHAR_P
|
||||
@ -1397,8 +1415,9 @@ malloc_init_hard_recursible(void)
|
||||
|
||||
ncpus = malloc_ncpus();
|
||||
|
||||
#if (!defined(JEMALLOC_MUTEX_INIT_CB) && !defined(JEMALLOC_ZONE) \
|
||||
&& !defined(_WIN32) && !defined(__native_client__))
|
||||
#if (defined(JEMALLOC_HAVE_PTHREAD_ATFORK) && !defined(JEMALLOC_MUTEX_INIT_CB) \
|
||||
&& !defined(JEMALLOC_ZONE) && !defined(_WIN32) && \
|
||||
!defined(__native_client__))
|
||||
/* LinuxThreads' pthread_atfork() allocates. */
|
||||
if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent,
|
||||
jemalloc_postfork_child) != 0) {
|
||||
@ -1977,8 +1996,8 @@ je_realloc(void *ptr, size_t size)
|
||||
*tsd_thread_deallocatedp_get(tsd) += old_usize;
|
||||
}
|
||||
UTRACE(ptr, size, ret);
|
||||
JEMALLOC_VALGRIND_REALLOC(true, tsdn, ret, usize, true, ptr, old_usize,
|
||||
old_rzsize, true, false);
|
||||
JEMALLOC_VALGRIND_REALLOC(maybe, tsdn, ret, usize, maybe, ptr,
|
||||
old_usize, old_rzsize, maybe, false);
|
||||
witness_assert_lockless(tsdn);
|
||||
return (ret);
|
||||
}
|
||||
@ -2404,8 +2423,8 @@ je_rallocx(void *ptr, size_t size, int flags)
|
||||
*tsd_thread_deallocatedp_get(tsd) += old_usize;
|
||||
}
|
||||
UTRACE(ptr, size, p);
|
||||
JEMALLOC_VALGRIND_REALLOC(true, tsd_tsdn(tsd), p, usize, false, ptr,
|
||||
old_usize, old_rzsize, false, zero);
|
||||
JEMALLOC_VALGRIND_REALLOC(maybe, tsd_tsdn(tsd), p, usize, no, ptr,
|
||||
old_usize, old_rzsize, no, zero);
|
||||
witness_assert_lockless(tsd_tsdn(tsd));
|
||||
return (p);
|
||||
label_oom:
|
||||
@ -2547,8 +2566,8 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags)
|
||||
*tsd_thread_allocatedp_get(tsd) += usize;
|
||||
*tsd_thread_deallocatedp_get(tsd) += old_usize;
|
||||
}
|
||||
JEMALLOC_VALGRIND_REALLOC(false, tsd_tsdn(tsd), ptr, usize, false, ptr,
|
||||
old_usize, old_rzsize, false, zero);
|
||||
JEMALLOC_VALGRIND_REALLOC(no, tsd_tsdn(tsd), ptr, usize, no, ptr,
|
||||
old_usize, old_rzsize, no, zero);
|
||||
label_not_resized:
|
||||
UTRACE(ptr, size, ptr);
|
||||
witness_assert_lockless(tsd_tsdn(tsd));
|
||||
|
@ -170,15 +170,16 @@ pages_purge(void *addr, size_t size)
|
||||
#ifdef _WIN32
|
||||
VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE);
|
||||
unzeroed = true;
|
||||
#elif defined(JEMALLOC_HAVE_MADVISE)
|
||||
# ifdef JEMALLOC_PURGE_MADVISE_DONTNEED
|
||||
# define JEMALLOC_MADV_PURGE MADV_DONTNEED
|
||||
# define JEMALLOC_MADV_ZEROS true
|
||||
# elif defined(JEMALLOC_PURGE_MADVISE_FREE)
|
||||
#elif (defined(JEMALLOC_PURGE_MADVISE_FREE) || \
|
||||
defined(JEMALLOC_PURGE_MADVISE_DONTNEED))
|
||||
# if defined(JEMALLOC_PURGE_MADVISE_FREE)
|
||||
# define JEMALLOC_MADV_PURGE MADV_FREE
|
||||
# define JEMALLOC_MADV_ZEROS false
|
||||
# elif defined(JEMALLOC_PURGE_MADVISE_DONTNEED)
|
||||
# define JEMALLOC_MADV_PURGE MADV_DONTNEED
|
||||
# define JEMALLOC_MADV_ZEROS true
|
||||
# else
|
||||
# error "No madvise(2) flag defined for purging unused dirty pages."
|
||||
# error No madvise(2) flag defined for purging unused dirty pages
|
||||
# endif
|
||||
int err = madvise(addr, size, JEMALLOC_MADV_PURGE);
|
||||
unzeroed = (!JEMALLOC_MADV_ZEROS || err != 0);
|
||||
@ -191,6 +192,34 @@ pages_purge(void *addr, size_t size)
|
||||
return (unzeroed);
|
||||
}
|
||||
|
||||
bool
|
||||
pages_huge(void *addr, size_t size)
|
||||
{
|
||||
|
||||
assert(PAGE_ADDR2BASE(addr) == addr);
|
||||
assert(PAGE_CEILING(size) == size);
|
||||
|
||||
#ifdef JEMALLOC_THP
|
||||
return (madvise(addr, size, MADV_HUGEPAGE) != 0);
|
||||
#else
|
||||
return (false);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
pages_nohuge(void *addr, size_t size)
|
||||
{
|
||||
|
||||
assert(PAGE_ADDR2BASE(addr) == addr);
|
||||
assert(PAGE_CEILING(size) == size);
|
||||
|
||||
#ifdef JEMALLOC_THP
|
||||
return (madvise(addr, size, MADV_NOHUGEPAGE) != 0);
|
||||
#else
|
||||
return (false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT
|
||||
static bool
|
||||
os_overcommits_sysctl(void)
|
||||
@ -219,7 +248,7 @@ os_overcommits_proc(void)
|
||||
char buf[1];
|
||||
ssize_t nread;
|
||||
|
||||
#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_open)
|
||||
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open)
|
||||
fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY);
|
||||
#else
|
||||
fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY);
|
||||
@ -227,13 +256,13 @@ os_overcommits_proc(void)
|
||||
if (fd == -1)
|
||||
return (false); /* Error. */
|
||||
|
||||
#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_read)
|
||||
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_read)
|
||||
nread = (ssize_t)syscall(SYS_read, fd, &buf, sizeof(buf));
|
||||
#else
|
||||
nread = read(fd, &buf, sizeof(buf));
|
||||
#endif
|
||||
|
||||
#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_close)
|
||||
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_close)
|
||||
syscall(SYS_close, fd);
|
||||
#else
|
||||
close(fd);
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#define CTL_GET(n, v, t) do { \
|
||||
size_t sz = sizeof(t); \
|
||||
xmallctl(n, v, &sz, NULL, 0); \
|
||||
xmallctl(n, (void *)v, &sz, NULL, 0); \
|
||||
} while (0)
|
||||
|
||||
#define CTL_M2_GET(n, i, v, t) do { \
|
||||
@ -12,7 +12,7 @@
|
||||
size_t sz = sizeof(t); \
|
||||
xmallctlnametomib(n, mib, &miblen); \
|
||||
mib[2] = (i); \
|
||||
xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
|
||||
xmallctlbymib(mib, miblen, (void *)v, &sz, NULL, 0); \
|
||||
} while (0)
|
||||
|
||||
#define CTL_M2_M4_GET(n, i, j, v, t) do { \
|
||||
@ -22,7 +22,7 @@
|
||||
xmallctlnametomib(n, mib, &miblen); \
|
||||
mib[2] = (i); \
|
||||
mib[4] = (j); \
|
||||
xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
|
||||
xmallctlbymib(mib, miblen, (void *)v, &sz, NULL, 0); \
|
||||
} while (0)
|
||||
|
||||
/******************************************************************************/
|
||||
@ -647,7 +647,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||
#define OPT_WRITE_BOOL_MUTABLE(n, m, c) { \
|
||||
bool bv2; \
|
||||
if (je_mallctl("opt."#n, (void *)&bv, &bsz, NULL, 0) == 0 && \
|
||||
je_mallctl(#m, &bv2, &bsz, NULL, 0) == 0) { \
|
||||
je_mallctl(#m, &bv2, (void *)&bsz, NULL, 0) == 0) { \
|
||||
if (json) { \
|
||||
malloc_cprintf(write_cb, cbopaque, \
|
||||
"\t\t\t\""#n"\": %s%s\n", bv ? "true" : \
|
||||
@ -692,7 +692,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||
#define OPT_WRITE_SSIZE_T_MUTABLE(n, m, c) { \
|
||||
ssize_t ssv2; \
|
||||
if (je_mallctl("opt."#n, (void *)&ssv, &sssz, NULL, 0) == 0 && \
|
||||
je_mallctl(#m, &ssv2, &sssz, NULL, 0) == 0) { \
|
||||
je_mallctl(#m, (void *)&ssv2, &sssz, NULL, 0) == 0) { \
|
||||
if (json) { \
|
||||
malloc_cprintf(write_cb, cbopaque, \
|
||||
"\t\t\t\""#n"\": %zd%s\n", ssv, (c)); \
|
||||
@ -1084,7 +1084,8 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||
* */
|
||||
epoch = 1;
|
||||
u64sz = sizeof(uint64_t);
|
||||
err = je_mallctl("epoch", &epoch, &u64sz, &epoch, sizeof(uint64_t));
|
||||
err = je_mallctl("epoch", (void *)&epoch, &u64sz, (void *)&epoch,
|
||||
sizeof(uint64_t));
|
||||
if (err != 0) {
|
||||
if (err == EAGAIN) {
|
||||
malloc_write("<jemalloc>: Memory allocation failure in "
|
||||
|
@ -517,12 +517,12 @@ tcache_boot(tsdn_t *tsdn)
|
||||
* If necessary, clamp opt_lg_tcache_max, now that large_maxclass is
|
||||
* known.
|
||||
*/
|
||||
if (opt_lg_tcache_max < 0 || (1U << opt_lg_tcache_max) < SMALL_MAXCLASS)
|
||||
if (opt_lg_tcache_max < 0 || (ZU(1) << opt_lg_tcache_max) < SMALL_MAXCLASS)
|
||||
tcache_maxclass = SMALL_MAXCLASS;
|
||||
else if ((1U << opt_lg_tcache_max) > large_maxclass)
|
||||
else if ((ZU(1) << opt_lg_tcache_max) > large_maxclass)
|
||||
tcache_maxclass = large_maxclass;
|
||||
else
|
||||
tcache_maxclass = (1U << opt_lg_tcache_max);
|
||||
tcache_maxclass = (ZU(1) << opt_lg_tcache_max);
|
||||
|
||||
nhbins = size2index(tcache_maxclass) + 1;
|
||||
|
||||
|
@ -49,7 +49,7 @@ static void
|
||||
wrtmessage(void *cbopaque, const char *s)
|
||||
{
|
||||
|
||||
#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_write)
|
||||
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_write)
|
||||
/*
|
||||
* Use syscall(2) rather than write(2) when possible in order to avoid
|
||||
* the possibility of memory allocation within libc. This is necessary
|
||||
@ -216,7 +216,7 @@ malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base)
|
||||
p++;
|
||||
}
|
||||
if (neg)
|
||||
ret = -ret;
|
||||
ret = (uintmax_t)(-((intmax_t)ret));
|
||||
|
||||
if (p == ns) {
|
||||
/* No conversion performed. */
|
||||
|
@ -520,7 +520,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
|
||||
return (0); /* Standard: return 0 for end-of-string. */
|
||||
cnt = utf8_count[ch];
|
||||
|
||||
/* Invalide sequence or there are not plenty bytes. */
|
||||
/* Invalid sequence or there are not plenty bytes. */
|
||||
if (n < (size_t)cnt)
|
||||
return (-1);
|
||||
|
||||
@ -559,7 +559,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* The code point larger than 0x10FFFF is not leagal
|
||||
/* The code point larger than 0x10FFFF is not legal
|
||||
* Unicode values. */
|
||||
if (wc > 0x10FFFF)
|
||||
return (-1);
|
||||
|
@ -521,7 +521,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
|
||||
return (0); /* Standard: return 0 for end-of-string. */
|
||||
cnt = utf8_count[ch];
|
||||
|
||||
/* Invalide sequence or there are not plenty bytes. */
|
||||
/* Invalid sequence or there are not plenty bytes. */
|
||||
if (n < (size_t)cnt)
|
||||
return (-1);
|
||||
|
||||
@ -560,7 +560,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* The code point larger than 0x10FFFF is not leagal
|
||||
/* The code point larger than 0x10FFFF is not legal
|
||||
* Unicode values. */
|
||||
if (wc > 0x10FFFF)
|
||||
return (-1);
|
||||
|
@ -690,7 +690,7 @@ translate_acl(struct archive_read_disk *a,
|
||||
#ifdef ACL_TYPE_NFS4
|
||||
if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
|
||||
/*
|
||||
* acl_get_entry_type_np() falis with non-NFSv4 ACLs
|
||||
* acl_get_entry_type_np() fails with non-NFSv4 ACLs
|
||||
*/
|
||||
if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {
|
||||
archive_set_error(&a->archive, errno, "Failed "
|
||||
@ -1194,7 +1194,7 @@ setup_sparse_fiemap(struct archive_read_disk *a,
|
||||
if (r < 0) {
|
||||
/* When something error happens, it is better we
|
||||
* should return ARCHIVE_OK because an earlier
|
||||
* version(<2.6.28) cannot perfom FS_IOC_FIEMAP. */
|
||||
* version(<2.6.28) cannot perform FS_IOC_FIEMAP. */
|
||||
goto exit_setup_sparse_fiemap;
|
||||
}
|
||||
if (fm->fm_mapped_extents == 0) {
|
||||
@ -1354,7 +1354,7 @@ setup_sparse(struct archive_read_disk *a,
|
||||
goto exit_setup_sparse;
|
||||
}
|
||||
if (off_s == 0 && off_e == size)
|
||||
break;/* This is not spase. */
|
||||
break;/* This is not sparse. */
|
||||
archive_entry_sparse_add_entry(entry, off_s,
|
||||
off_e - off_s);
|
||||
off_s = off_e;
|
||||
|
@ -511,6 +511,13 @@ read_more:
|
||||
}
|
||||
llen = len;
|
||||
if ((nl == 0) && (uudecode->state != ST_UUEND)) {
|
||||
if (total == 0 && ravail <= 0) {
|
||||
/* There is nothing more to read, fail */
|
||||
archive_set_error(&self->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Missing format data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
/*
|
||||
* Save remaining data which does not contain
|
||||
* NL('\n','\r').
|
||||
@ -567,7 +574,7 @@ read_more:
|
||||
"Insufficient compressed data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
/* Get length of undecoded bytes of curent line. */
|
||||
/* Get length of undecoded bytes of current line. */
|
||||
l = UUDECODE(*b++);
|
||||
body--;
|
||||
if (l > body) {
|
||||
|
@ -260,7 +260,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
archive_entry_set_filetype(entry, AE_IFREG);
|
||||
/* Get the size of the filename table. */
|
||||
number = ar_atol10(h + AR_size_offset, AR_size_size);
|
||||
if (number > SIZE_MAX) {
|
||||
if (number > SIZE_MAX || number > 1024 * 1024 * 1024) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Filename table too large");
|
||||
return (ARCHIVE_FATAL);
|
||||
@ -342,16 +342,19 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
|
||||
/* Parse the size of the name, adjust the file size. */
|
||||
number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3);
|
||||
bsd_name_length = (size_t)number;
|
||||
/* Guard against the filename + trailing NUL
|
||||
* overflowing a size_t and against the filename size
|
||||
* being larger than the entire entry. */
|
||||
if (number > (uint64_t)(bsd_name_length + 1)
|
||||
|| (int64_t)bsd_name_length > ar->entry_bytes_remaining) {
|
||||
/* Sanity check the filename length:
|
||||
* = Must be <= SIZE_MAX - 1
|
||||
* = Must be <= 1MB
|
||||
* = Cannot be bigger than the entire entry
|
||||
*/
|
||||
if (number > SIZE_MAX - 1
|
||||
|| number > 1024 * 1024
|
||||
|| (int64_t)number > ar->entry_bytes_remaining) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Bad input file size");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
bsd_name_length = (size_t)number;
|
||||
ar->entry_bytes_remaining -= bsd_name_length;
|
||||
/* Adjust file size reported to client. */
|
||||
archive_entry_set_size(entry, ar->entry_bytes_remaining);
|
||||
|
@ -67,7 +67,7 @@ struct lzx_dec {
|
||||
/* The length how many bytes we can copy decoded code from
|
||||
* the window. */
|
||||
int copy_len;
|
||||
/* Translation reversal for x86 proccessor CALL byte sequence(E8).
|
||||
/* Translation reversal for x86 processor CALL byte sequence(E8).
|
||||
* This is used for LZX only. */
|
||||
uint32_t translation_size;
|
||||
char translation;
|
||||
@ -1555,7 +1555,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
|
||||
/*
|
||||
* Note: I suspect there is a bug in makecab.exe because, in rare
|
||||
* case, compressed bytes are still remaining regardless we have
|
||||
* gotten all uncompressed bytes, which size is recoded in CFDATA,
|
||||
* gotten all uncompressed bytes, which size is recorded in CFDATA,
|
||||
* as much as we need, and we have to use the garbage so as to
|
||||
* correctly compute the sum of CFDATA accordingly.
|
||||
*/
|
||||
@ -1742,7 +1742,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
|
||||
}
|
||||
|
||||
/*
|
||||
* Translation reversal of x86 proccessor CALL byte sequence(E8).
|
||||
* Translation reversal of x86 processor CALL byte sequence(E8).
|
||||
*/
|
||||
lzx_translation(&cab->xstrm, cab->uncompressed_buffer,
|
||||
cfdata->uncompressed_size,
|
||||
@ -2271,7 +2271,7 @@ static int
|
||||
lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
|
||||
{
|
||||
/*
|
||||
* x86 proccessor family can read misaligned data without an access error.
|
||||
* x86 processor family can read misaligned data without an access error.
|
||||
*/
|
||||
int n = CACHE_BITS - br->cache_avail;
|
||||
|
||||
|
@ -299,14 +299,21 @@ archive_read_format_tar_cleanup(struct archive_read *a)
|
||||
*
|
||||
* This has to be pretty lenient in order to accomodate the enormous
|
||||
* variety of tar writers in the world:
|
||||
* = POSIX ustar requires octal values with leading zeros and
|
||||
* specific termination on fields
|
||||
* = POSIX (IEEE Std 1003.1-1988) ustar requires octal values with leading
|
||||
* zeros and allows fields to be terminated with space or null characters
|
||||
* = Many writers use different termination (in particular, libarchive
|
||||
* omits terminator bytes to squeeze one or two more digits)
|
||||
* = Many writers pad with space and omit leading zeros
|
||||
* = GNU tar and star write base-256 values if numbers are too
|
||||
* big to be represented in octal
|
||||
*
|
||||
* Examples of specific tar headers that we should support:
|
||||
* = Perl Archive::Tar terminates uid, gid, devminor and devmajor with two
|
||||
* null bytes, pads size with spaces and other numeric fields with zeroes
|
||||
* = plexus-archiver prior to 2.6.3 (before switching to commons-compress)
|
||||
* may have uid and gid fields filled with spaces without any octal digits
|
||||
* at all and pads all numeric fields with spaces
|
||||
*
|
||||
* This should tolerate all variants in use. It will reject a field
|
||||
* where the writer just left garbage after a trailing NUL.
|
||||
*/
|
||||
@ -324,11 +331,7 @@ validate_number_field(const char* p_field, size_t i_size)
|
||||
while (i < i_size && p_field[i] == ' ') {
|
||||
++i;
|
||||
}
|
||||
/* Must be at least one octal digit. */
|
||||
if (i >= i_size || p_field[i] < '0' || p_field[i] > '7') {
|
||||
return 0;
|
||||
}
|
||||
/* Skip remaining octal digits. */
|
||||
/* Skip octal digits. */
|
||||
while (i < i_size && p_field[i] >= '0' && p_field[i] <= '7') {
|
||||
++i;
|
||||
}
|
||||
|
@ -2298,7 +2298,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
|
||||
return (0); /* Standard: return 0 for end-of-string. */
|
||||
cnt = utf8_count[ch];
|
||||
|
||||
/* Invalide sequence or there are not plenty bytes. */
|
||||
/* Invalid sequence or there are not plenty bytes. */
|
||||
if ((int)n < cnt) {
|
||||
cnt = (int)n;
|
||||
for (i = 1; i < cnt; i++) {
|
||||
@ -2379,7 +2379,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
|
||||
goto invalid_sequence;
|
||||
}
|
||||
|
||||
/* The code point larger than 0x10FFFF is not leagal
|
||||
/* The code point larger than 0x10FFFF is not legal
|
||||
* Unicode values. */
|
||||
if (wc > UNICODE_MAX)
|
||||
goto invalid_sequence;
|
||||
@ -2397,7 +2397,7 @@ utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
|
||||
int cnt;
|
||||
|
||||
cnt = _utf8_to_unicode(pwc, s, n);
|
||||
/* Any of Surrogate pair is not leagal Unicode values. */
|
||||
/* Any of Surrogate pair is not legal Unicode values. */
|
||||
if (cnt == 3 && IS_SURROGATE_PAIR_LA(*pwc))
|
||||
return (-3);
|
||||
return (cnt);
|
||||
@ -2458,7 +2458,7 @@ invalid_sequence:
|
||||
/*
|
||||
* Convert a Unicode code point to a single UTF-8 sequence.
|
||||
*
|
||||
* NOTE:This function does not check if the Unicode is leagal or not.
|
||||
* NOTE:This function does not check if the Unicode is legal or not.
|
||||
* Please you definitely check it before calling this.
|
||||
*/
|
||||
static size_t
|
||||
@ -2554,7 +2554,7 @@ utf16_to_unicode(uint32_t *pwc, const char *s, size_t n, int be)
|
||||
* Surrogate pair values(0xd800 through 0xdfff) are only
|
||||
* used by UTF-16, so, after above culculation, the code
|
||||
* must not be surrogate values, and Unicode has no codes
|
||||
* larger than 0x10ffff. Thus, those are not leagal Unicode
|
||||
* larger than 0x10ffff. Thus, those are not legal Unicode
|
||||
* values.
|
||||
*/
|
||||
if (IS_SURROGATE_PAIR_LA(uc) || uc > UNICODE_MAX) {
|
||||
|
@ -115,13 +115,13 @@ archive_string_conversion_set_opt(struct archive_string_conv *, int);
|
||||
|
||||
|
||||
/* Copy one archive_string to another in locale conversion.
|
||||
* Return -1 if conversion failes. */
|
||||
* Return -1 if conversion fails. */
|
||||
int
|
||||
archive_strncpy_l(struct archive_string *, const void *, size_t,
|
||||
struct archive_string_conv *);
|
||||
|
||||
/* Copy one archive_string to another in locale conversion.
|
||||
* Return -1 if conversion failes. */
|
||||
* Return -1 if conversion fails. */
|
||||
int
|
||||
archive_strncat_l(struct archive_string *, const void *, size_t,
|
||||
struct archive_string_conv *);
|
||||
|
@ -205,7 +205,7 @@ struct _7zip {
|
||||
/*
|
||||
* The list of the file entries which has its contents is used to
|
||||
* manage struct file objects.
|
||||
* We use 'next' a menber of struct file to chain.
|
||||
* We use 'next' (a member of struct file) to chain.
|
||||
*/
|
||||
struct {
|
||||
struct file *first;
|
||||
|
@ -289,7 +289,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
|
||||
sconv = get_sconv(a);
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Make sure the path separators in pahtname, hardlink and symlink
|
||||
/* Make sure the path separators in pathname, hardlink and symlink
|
||||
* are all slash '/', not the Windows path separator '\'. */
|
||||
entry_main = __la_win_entry_in_posix_pathseparator(entry);
|
||||
if (entry_main == NULL) {
|
||||
|
@ -232,7 +232,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
|
||||
sconv = get_sconv(a);
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Make sure the path separators in pahtname, hardlink and symlink
|
||||
/* Make sure the path separators in pathname, hardlink and symlink
|
||||
* are all slash '/', not the Windows path separator '\'. */
|
||||
entry_main = __la_win_entry_in_posix_pathseparator(entry);
|
||||
if (entry_main == NULL) {
|
||||
|
@ -119,9 +119,9 @@ static const char template_header[] = {
|
||||
'0','0','0','0','0','0', '0','\0',
|
||||
/* gid, null termination: 8 bytes */
|
||||
'0','0','0','0','0','0', '0','\0',
|
||||
/* size, space termation: 12 bytes */
|
||||
/* size, space termination: 12 bytes */
|
||||
'0','0','0','0','0','0','0','0','0','0','0', '\0',
|
||||
/* mtime, space termation: 12 bytes */
|
||||
/* mtime, space termination: 12 bytes */
|
||||
'0','0','0','0','0','0','0','0','0','0','0', '\0',
|
||||
/* Initial checksum value: 8 spaces */
|
||||
' ',' ',' ',' ',' ',' ',' ',' ',
|
||||
@ -368,7 +368,7 @@ archive_write_gnutar_header(struct archive_write *a,
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Make sure the path separators in pahtname, hardlink and symlink
|
||||
/* Make sure the path separators in pathname, hardlink and symlink
|
||||
* are all slash '/', not the Windows path separator '\'. */
|
||||
entry_main = __la_win_entry_in_posix_pathseparator(entry);
|
||||
if (entry_main == NULL) {
|
||||
|
@ -1840,9 +1840,9 @@ mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file,
|
||||
len = strlen(p);
|
||||
|
||||
/*
|
||||
* Add "./" prefiex.
|
||||
* Add "./" prefix.
|
||||
* NOTE: If the pathname does not have a path separator, we have
|
||||
* to add "./" to the head of the pathename because mtree reader
|
||||
* to add "./" to the head of the pathname because mtree reader
|
||||
* will suppose that it is v1(a.k.a classic) mtree format and
|
||||
* change the directory unexpectedly and so it will make a wrong
|
||||
* path.
|
||||
|
@ -709,7 +709,7 @@ archive_write_pax_header(struct archive_write *a,
|
||||
|
||||
/* Copy entry so we can modify it as needed. */
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Make sure the path separators in pahtname, hardlink and symlink
|
||||
/* Make sure the path separators in pathname, hardlink and symlink
|
||||
* are all slash '/', not the Windows path separator '\'. */
|
||||
entry_main = __la_win_entry_in_posix_pathseparator(entry_original);
|
||||
if (entry_main == entry_original)
|
||||
|
@ -114,9 +114,9 @@ static const char template_header[] = {
|
||||
'0','0','0','0','0','0', ' ','\0',
|
||||
/* gid, space-null termination: 8 bytes */
|
||||
'0','0','0','0','0','0', ' ','\0',
|
||||
/* size, space termation: 12 bytes */
|
||||
/* size, space termination: 12 bytes */
|
||||
'0','0','0','0','0','0','0','0','0','0','0', ' ',
|
||||
/* mtime, space termation: 12 bytes */
|
||||
/* mtime, space termination: 12 bytes */
|
||||
'0','0','0','0','0','0','0','0','0','0','0', ' ',
|
||||
/* Initial checksum value: 8 spaces */
|
||||
' ',' ',' ',' ',' ',' ',' ',' ',
|
||||
@ -336,7 +336,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Make sure the path separators in pahtname, hardlink and symlink
|
||||
/* Make sure the path separators in pathname, hardlink and symlink
|
||||
* are all slash '/', not the Windows path separator '\'. */
|
||||
entry_main = __la_win_entry_in_posix_pathseparator(entry);
|
||||
if (entry_main == NULL) {
|
||||
|
@ -98,9 +98,9 @@ static const char template_header[] = {
|
||||
'0','0','0','0','0','0', ' ','\0',
|
||||
/* gid, space-null termination: 8 bytes */
|
||||
'0','0','0','0','0','0', ' ','\0',
|
||||
/* size, space termation: 12 bytes */
|
||||
/* size, space termination: 12 bytes */
|
||||
'0','0','0','0','0','0','0','0','0','0','0', ' ',
|
||||
/* mtime, space termation: 12 bytes */
|
||||
/* mtime, space termination: 12 bytes */
|
||||
'0','0','0','0','0','0','0','0','0','0','0', ' ',
|
||||
/* Initial checksum value: 8 spaces */
|
||||
' ',' ',' ',' ',' ',' ',' ',' ',
|
||||
@ -314,7 +314,7 @@ archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry)
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Make sure the path separators in pahtname, hardlink and symlink
|
||||
/* Make sure the path separators in pathname, hardlink and symlink
|
||||
* are all slash '/', not the Windows path separator '\'. */
|
||||
entry_main = __la_win_entry_in_posix_pathseparator(entry);
|
||||
if (entry_main == NULL) {
|
||||
|
@ -592,7 +592,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
|
||||
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Make sure the path separators in pahtname, hardlink and symlink
|
||||
/* Make sure the path separators in pathname, hardlink and symlink
|
||||
* are all slash '/', not the Windows path separator '\'. */
|
||||
zip->entry = __la_win_entry_in_posix_pathseparator(entry);
|
||||
if (zip->entry == entry)
|
||||
|
@ -519,7 +519,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
|
||||
return (0); /* Standard: return 0 for end-of-string. */
|
||||
cnt = utf8_count[ch];
|
||||
|
||||
/* Invalide sequence or there are not plenty bytes. */
|
||||
/* Invalid sequence or there are not plenty bytes. */
|
||||
if (n < (size_t)cnt)
|
||||
return (-1);
|
||||
|
||||
@ -558,7 +558,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* The code point larger than 0x10FFFF is not leagal
|
||||
/* The code point larger than 0x10FFFF is not legal
|
||||
* Unicode values. */
|
||||
if (wc > 0x10FFFF)
|
||||
return (-1);
|
||||
|
@ -66,7 +66,7 @@ DEFINE_TEST(test_archive_cmdline)
|
||||
assertEqualString("gzip", cl->argv[0]);
|
||||
assertEqualInt(ARCHIVE_OK, __archive_cmdline_free(cl));
|
||||
|
||||
/* A command line includes space characer. */
|
||||
/* A command line includes space character. */
|
||||
assert((cl = __archive_cmdline_allocate()) != NULL);
|
||||
if (cl == NULL)
|
||||
return;
|
||||
@ -78,7 +78,7 @@ DEFINE_TEST(test_archive_cmdline)
|
||||
assertEqualString("gzip ", cl->argv[0]);
|
||||
assertEqualInt(ARCHIVE_OK, __archive_cmdline_free(cl));
|
||||
|
||||
/* A command line includes space characer: pattern 2.*/
|
||||
/* A command line includes space character: pattern 2.*/
|
||||
assert((cl = __archive_cmdline_allocate()) != NULL);
|
||||
if (cl == NULL)
|
||||
return;
|
||||
@ -90,7 +90,7 @@ DEFINE_TEST(test_archive_cmdline)
|
||||
assertEqualString("gzip x", cl->argv[0]);
|
||||
assertEqualInt(ARCHIVE_OK, __archive_cmdline_free(cl));
|
||||
|
||||
/* A command line includes space characer: pattern 3.*/
|
||||
/* A command line includes space character: pattern 3.*/
|
||||
assert((cl = __archive_cmdline_allocate()) != NULL);
|
||||
if (cl == NULL)
|
||||
return;
|
||||
@ -103,7 +103,7 @@ DEFINE_TEST(test_archive_cmdline)
|
||||
assertEqualString("gzip x s ", cl->argv[0]);
|
||||
assertEqualInt(ARCHIVE_OK, __archive_cmdline_free(cl));
|
||||
|
||||
/* A command line includes space characer: pattern 4.*/
|
||||
/* A command line includes space character: pattern 4.*/
|
||||
assert((cl = __archive_cmdline_allocate()) != NULL);
|
||||
if (cl == NULL)
|
||||
return;
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Martin Matuska
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "test.h"
|
||||
__FBSDID("$FreeBSD");
|
||||
|
||||
/*
|
||||
* Verify our ability to read sample files created by plexus-archiver version
|
||||
* 2.6.2 and lower (project switched to Apache Commons Compress with 2.6.3).
|
||||
*
|
||||
* These files may have tar entries with uid and gid header fields filled with
|
||||
* spaces without any octal digit.
|
||||
*/
|
||||
|
||||
DEFINE_TEST(test_compat_plexus_archiver_tar)
|
||||
{
|
||||
char name[] = "test_compat_plexus_archiver_tar.tar";
|
||||
struct archive_entry *ae;
|
||||
struct archive *a;
|
||||
int r;
|
||||
|
||||
assert((a = archive_read_new()) != NULL);
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
|
||||
extract_reference_file(name);
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name,
|
||||
10240));
|
||||
|
||||
/* Read first entry. */
|
||||
assertEqualIntA(a, ARCHIVE_OK, r = archive_read_next_header(a, &ae));
|
||||
if (r != ARCHIVE_OK) {
|
||||
archive_read_free(a);
|
||||
return;
|
||||
}
|
||||
assertEqualString("commons-logging-1.2/NOTICE.txt",
|
||||
archive_entry_pathname(ae));
|
||||
assertEqualInt(1404583896, archive_entry_mtime(ae));
|
||||
assertEqualInt(0100664, archive_entry_mode(ae));
|
||||
assertEqualInt(0, archive_entry_uid(ae));
|
||||
assertEqualInt(0, archive_entry_gid(ae));
|
||||
|
||||
/* Verify that the format detection worked. */
|
||||
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
|
||||
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
|
||||
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_close(a));
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
begin 644 test_compat_plexus_archiver_tar.tar
|
||||
M8V]M;6]N<RUL;V=G:6YG+3$N,B].3U1)0T4N='AT````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M`````````````#$P,#8V-"``("`@("`@(``@("`@("`@`"`@("`@("`@,C8Q
|
||||
M(#$R,S4V,#,W-S,P("`Q-#$U-P`@,```````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M``````````````````````````````````````````!U<W1A<@```'1N````
|
||||
M````````````````````````````````````=&X`````````````````````
|
||||
M```````````````````@("`@(#`@`"`@("`@,"``````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M``````````````````````!!<&%C:&4@0V]M;6]N<R!,;V=G:6YG"D-O<'ER
|
||||
M:6=H="`R,#`S+3(P,30@5&AE($%P86-H92!3;V9T=V%R92!&;W5N9&%T:6]N
|
||||
M"@I4:&ES('!R;V1U8W0@:6YC;'5D97,@<V]F='=A<F4@9&5V96QO<&5D(&%T
|
||||
M"E1H92!!<&%C:&4@4V]F='=A<F4@1F]U;F1A=&EO;B`H:'1T<#HO+W=W=RYA
|
||||
M<&%C:&4N;W)G+RDN"@H`````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
7``````````````````````````````H`
|
||||
`
|
||||
end
|
@ -353,12 +353,14 @@ makeextralist(int flags, const char *src)
|
||||
wchar_t *dst, *d;
|
||||
size_t len;
|
||||
const wchar_t *s;
|
||||
mbstate_t mbstate;
|
||||
|
||||
bzero(&mbstate, sizeof(mbstate));
|
||||
len = strlen(src);
|
||||
if ((dst = calloc(len + MAXEXTRAS, sizeof(*dst))) == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((flags & VIS_NOLOCALE) || mbstowcs(dst, src, len) == (size_t)-1) {
|
||||
if ((flags & VIS_NOLOCALE) || mbsrtowcs(dst, &src, len, &mbstate) == (size_t)-1) {
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++)
|
||||
dst[i] = (wchar_t)(u_char)src[i];
|
||||
@ -400,6 +402,7 @@ istrsenvisx(char **mbdstp, size_t *dlen, const char *mbsrc, size_t mblength,
|
||||
int clen = 0, cerr, error = -1, i, shft;
|
||||
char *mbdst, *mdst;
|
||||
ssize_t mbslength, maxolen;
|
||||
mbstate_t mbstate;
|
||||
|
||||
_DIAGASSERT(mbdstp != NULL);
|
||||
_DIAGASSERT(mbsrc != NULL || mblength == 0);
|
||||
@ -456,10 +459,11 @@ istrsenvisx(char **mbdstp, size_t *dlen, const char *mbsrc, size_t mblength,
|
||||
*/
|
||||
if (mbslength == 1)
|
||||
mbslength++;
|
||||
bzero(&mbstate, sizeof(mbstate));
|
||||
while (mbslength > 0) {
|
||||
/* Convert one multibyte character to wchar_t. */
|
||||
if (!cerr)
|
||||
clen = mbtowc(src, mbsrc, MB_LEN_MAX);
|
||||
clen = mbrtowc(src, mbsrc, MB_LEN_MAX, &mbstate);
|
||||
if (cerr || clen < 0) {
|
||||
/* Conversion error, process as a byte instead. */
|
||||
*src = (wint_t)(u_char)*mbsrc;
|
||||
@ -530,9 +534,10 @@ istrsenvisx(char **mbdstp, size_t *dlen, const char *mbsrc, size_t mblength,
|
||||
len = wcslen(start);
|
||||
maxolen = dlen ? *dlen : (wcslen(start) * MB_LEN_MAX + 1);
|
||||
olen = 0;
|
||||
bzero(&mbstate, sizeof(mbstate));
|
||||
for (dst = start; len > 0; len--) {
|
||||
if (!cerr)
|
||||
clen = wctomb(mbdst, *dst);
|
||||
clen = wcrtomb(mbdst, *dst, &mbstate);
|
||||
if (cerr || clen < 0) {
|
||||
/*
|
||||
* Conversion error, process as a byte(s) instead.
|
||||
|
@ -1479,8 +1479,27 @@ LazyValueInfo LazyValueAnalysis::run(Function &F, FunctionAnalysisManager &FAM)
|
||||
return LazyValueInfo(&AC, &TLI, DT);
|
||||
}
|
||||
|
||||
|
||||
/// Returns true if we can statically tell that this value will never be a
|
||||
/// "useful" constant. In practice, this means we've got something like an
|
||||
/// alloca or a malloc call for which a comparison against a constant can
|
||||
/// only be guarding dead code. Note that we are potentially giving up some
|
||||
/// precision in dead code (a constant result) in favour of avoiding a
|
||||
/// expensive search for a easily answered common query.
|
||||
static bool isKnownNonConstant(Value *V) {
|
||||
V = V->stripPointerCasts();
|
||||
// The return val of alloc cannot be a Constant.
|
||||
if (isa<AllocaInst>(V))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Constant *LazyValueInfo::getConstant(Value *V, BasicBlock *BB,
|
||||
Instruction *CxtI) {
|
||||
// Bail out early if V is known not to be a Constant.
|
||||
if (isKnownNonConstant(V))
|
||||
return nullptr;
|
||||
|
||||
const DataLayout &DL = BB->getModule()->getDataLayout();
|
||||
LVILatticeVal Result =
|
||||
getCache(PImpl, AC, &DL, DT).getValueInBlock(V, BB, CxtI);
|
||||
@ -1613,6 +1632,17 @@ LazyValueInfo::getPredicateOnEdge(unsigned Pred, Value *V, Constant *C,
|
||||
LazyValueInfo::Tristate
|
||||
LazyValueInfo::getPredicateAt(unsigned Pred, Value *V, Constant *C,
|
||||
Instruction *CxtI) {
|
||||
// Is or is not NonNull are common predicates being queried. If
|
||||
// isKnownNonNull can tell us the result of the predicate, we can
|
||||
// return it quickly. But this is only a fastpath, and falling
|
||||
// through would still be correct.
|
||||
if (V->getType()->isPointerTy() && C->isNullValue() &&
|
||||
isKnownNonNull(V->stripPointerCasts())) {
|
||||
if (Pred == ICmpInst::ICMP_EQ)
|
||||
return LazyValueInfo::False;
|
||||
else if (Pred == ICmpInst::ICMP_NE)
|
||||
return LazyValueInfo::True;
|
||||
}
|
||||
const DataLayout &DL = CxtI->getModule()->getDataLayout();
|
||||
LVILatticeVal Result = getCache(PImpl, AC, &DL, DT).getValueAt(V, CxtI);
|
||||
Tristate Ret = getPredicateResult(Pred, C, Result, DL, TLI);
|
||||
|
@ -137,16 +137,10 @@ ATF_TC_BODY(mbtowc, tc)
|
||||
h_mbtowc("ja_JP.ISO2022-JP", "\033$B", "\033$B$\"\033(B");
|
||||
h_mbtowc("ja_JP.SJIS", "\202", "\202\240");
|
||||
h_mbtowc("ja_JP.eucJP", "\244", "\244\242");
|
||||
#ifndef __FreeBSD__
|
||||
/* Moved last as it fails */
|
||||
h_mbtowc("zh_CN.GB18030", "\241", "\241\241");
|
||||
#endif
|
||||
h_mbtowc("zh_TW.Big5", "\241", "\241@");
|
||||
h_mbtowc("zh_TW.eucTW", "\241", "\241\241");
|
||||
#ifdef __FreeBSD__
|
||||
atf_tc_expect_fail("zh_CN.GB18030");
|
||||
h_mbtowc("zh_CN.GB18030", "\241", "\241\241");
|
||||
#endif
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
|
@ -1919,7 +1919,7 @@ main(int argc, char **argv)
|
||||
error("%s", pcap_geterr(pd));
|
||||
#ifdef HAVE_CASPER
|
||||
if (RFileName == NULL && VFileName == NULL) {
|
||||
static const unsigned long cmds[] = { BIOCGSTATS };
|
||||
static const unsigned long cmds[] = { BIOCGSTATS, BIOCROTZBUF };
|
||||
|
||||
/*
|
||||
* The various libpcap devices use a combination of
|
||||
|
@ -1159,7 +1159,7 @@ addarg(char **argv, const char *val)
|
||||
*/
|
||||
argv = (char **)malloc(sizeof(*argv) * 12);
|
||||
if (argv == NULL)
|
||||
return(NULL);
|
||||
fatal(net, "failure allocating argument space");
|
||||
*argv++ = (char *)10;
|
||||
*argv = (char *)0;
|
||||
}
|
||||
@ -1170,11 +1170,12 @@ addarg(char **argv, const char *val)
|
||||
*argv = (char *)((long)(*argv) + 10);
|
||||
argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2));
|
||||
if (argv == NULL)
|
||||
return(NULL);
|
||||
fatal(net, "failure allocating argument space");
|
||||
argv++;
|
||||
cpp = &argv[(long)argv[-1] - 10];
|
||||
}
|
||||
*cpp++ = strdup(val);
|
||||
if ((*cpp++ = strdup(val)) == NULL)
|
||||
fatal(net, "failure allocating argument space");
|
||||
*cpp = 0;
|
||||
return(argv);
|
||||
}
|
||||
|
@ -18,10 +18,10 @@ data should contain commentary citing reliable sources as
|
||||
justification.
|
||||
|
||||
Please submit changes against either the latest release in
|
||||
<ftp://ftp.iana.org/tz/> or the master branch of the experimental
|
||||
Git repository. If you use Git the following workflow may be helpful:
|
||||
<ftp://ftp.iana.org/tz/> or the master branch of the development
|
||||
repository. If you use Git the following workflow may be helpful:
|
||||
|
||||
* Copy the experimental repository.
|
||||
* Copy the development repository.
|
||||
|
||||
git clone https://github.com/eggert/tz.git
|
||||
cd tz
|
||||
|
@ -542,7 +542,8 @@ force_tzs: $(TZS_NEW)
|
||||
cp $(TZS_NEW) $(TZS)
|
||||
|
||||
libtz.a: $(LIBOBJS)
|
||||
$(AR) ru $@ $(LIBOBJS)
|
||||
rm -f $@
|
||||
$(AR) -rc $@ $(LIBOBJS)
|
||||
$(RANLIB) $@
|
||||
|
||||
date: $(DATEOBJS)
|
||||
|
@ -1,5 +1,46 @@
|
||||
News for the tz database
|
||||
|
||||
Release 2016j - 2016-11-22 23:17:13 -0800
|
||||
|
||||
Briefly: Saratov, Russia moves from +03 to +04 on 2016-12-04.
|
||||
|
||||
Changes to future time stamps
|
||||
|
||||
Saratov, Russia switches from +03 to +04 on 2016-12-04 at 02:00.
|
||||
This hives off a new zone Europe/Saratov from Europe/Volgograd.
|
||||
(Thanks to Yuri Konotopov and Stepan Golosunov.)
|
||||
|
||||
Changes to past time stamps
|
||||
|
||||
The new zone Asia/Atyrau for Atyraū Region, Kazakhstan, is like
|
||||
Asia/Aqtau except it switched from +04/+05 to +05/+06 in spring
|
||||
1999, not fall 1994. (Thanks to Stepan Golosunov.)
|
||||
|
||||
Changes to past time zone abbreviations
|
||||
|
||||
Asia/Gaza and Asia/Hebron now use "EEST", not "EET", to denote
|
||||
summer time before 1948. The old use of "EET" was a typo.
|
||||
|
||||
Changes to code
|
||||
|
||||
zic no longer mishandles file systems that lack hard links, fixing
|
||||
bugs introduced in 2016g. (Problems reported by Tom Lane.)
|
||||
Also, when the destination already contains symbolic links, zic
|
||||
should now work better on systems where the 'link' system call
|
||||
does not follow symbolic links.
|
||||
|
||||
Changes to documentation and commentary
|
||||
|
||||
tz-link.htm now documents the relationship between release version
|
||||
numbers and development-repository commit tags. (Suggested by
|
||||
Paul Koning.)
|
||||
|
||||
The 'Theory' file now documents UT.
|
||||
|
||||
iso3166.tab now accents "Curaçao", and commentary now mentions
|
||||
the names "Cabo Verde" and "Czechia". (Thanks to Jiří Boháč.)
|
||||
|
||||
|
||||
Release 2016i - 2016-11-01 23:19:52 -0700
|
||||
|
||||
Briefly: Cyprus split into two time zones on 2016-10-30, and Tonga
|
||||
@ -212,7 +253,7 @@ Release 2016g - 2016-09-13 08:56:38 -0700
|
||||
23 commits and some working-file changes have been made since
|
||||
release 2016g, the version number is now something like
|
||||
'2016g-23-g50556e3-dirty' instead of the misleading '2016g'.
|
||||
Official releases uses the same version number format as before,
|
||||
Tagged releases use the same version number format as before,
|
||||
e.g., '2016g'. To support the more-accurate version number, its
|
||||
specification has moved from a line in the Makefile to a new
|
||||
source file 'version'.
|
||||
|
@ -10,24 +10,9 @@ locations around the globe. It is updated periodically to reflect
|
||||
changes made by political bodies to time zone boundaries, UTC offsets,
|
||||
and daylight-saving rules.
|
||||
|
||||
Here is a recipe for acquiring, building, installing, and testing the
|
||||
tz distribution on a GNU/Linux or similar host.
|
||||
|
||||
To acquire the distribution, run the following shell commands:
|
||||
|
||||
mkdir tz
|
||||
cd tz
|
||||
wget --retr-symlinks 'ftp://ftp.iana.org/tz/tz*-latest.tar.gz'
|
||||
gzip -dc tzcode-latest.tar.gz | tar -xf -
|
||||
gzip -dc tzdata-latest.tar.gz | tar -xf -
|
||||
|
||||
Alternatively, the following shell commands acquire the same
|
||||
distribution, with extra data useful for regression testing:
|
||||
|
||||
wget --retr-symlinks 'ftp://ftp.iana.org/tz/tzdb-latest.tar.lz'
|
||||
lzip -dc tzdb-latest.tar.lz | tar -xf -
|
||||
|
||||
Be sure to read the comments in "Makefile" and make any changes needed
|
||||
See <https://www.iana.org/time-zones/repository/tz-link.html> or the
|
||||
file tz-link.htm for how to acquire the code and data. Once acquired,
|
||||
read the comments in the file 'Makefile' and make any changes needed
|
||||
to make things right for your system, especially if you are using some
|
||||
platform other than GNU/Linux. Then run the following commands,
|
||||
substituting your desired installation directory for "$HOME/tzdir":
|
||||
@ -60,10 +45,6 @@ Thanks in particular to Arthur David Olson, the project's founder and first
|
||||
maintainer, to whom the time zone community owes the greatest debt of all.
|
||||
None of them are responsible for remaining errors.
|
||||
|
||||
Look in <ftp://ftp.iana.org/tz/releases/> for updated versions of these files.
|
||||
|
||||
Please send comments or information to tz@iana.org.
|
||||
|
||||
-----
|
||||
|
||||
This file is in the public domain, so clarified as of 2009-05-17 by
|
||||
|
@ -8,6 +8,7 @@ Theory and pragmatics of the tz code and data
|
||||
Time zone abbreviations
|
||||
Accuracy of the tz database
|
||||
Time and date functions
|
||||
Interface stability
|
||||
Calendrical issues
|
||||
Time and time zones on Mars
|
||||
|
||||
@ -342,12 +343,24 @@ Errors in the tz database arise from many sources:
|
||||
non-hour-based system at night.
|
||||
|
||||
* Early clocks were less reliable, and data entries do not represent
|
||||
this unreliability.
|
||||
clock error.
|
||||
|
||||
* As for leap seconds, civil time was not based on atomic time before
|
||||
1972, and we don't know the history of earth's rotation accurately
|
||||
enough to map SI seconds to historical solar time to more than
|
||||
about one-hour accuracy. See: Morrison LV, Stephenson FR.
|
||||
* The tz database assumes Universal Time (UT) as an origin, even
|
||||
though UT is not standardized for older time stamps. In the tz
|
||||
database commentary, UT denotes a family of time standards that
|
||||
includes Coordinated Universal Time (UTC) along with other variants
|
||||
such as UT1 and GMT, with days starting at midnight. Although UT
|
||||
equals UTC for modern time stamps, UTC was not defined until 1960,
|
||||
so commentary uses the more-general abbreviation UT for time stamps
|
||||
that might predate 1960. Since UT, UT1, etc. disagree slightly,
|
||||
and since pre-1972 UTC seconds varied in length, interpretation of
|
||||
older time stamps can be problematic when subsecond accuracy is
|
||||
needed.
|
||||
|
||||
* Civil time was not based on atomic time before 1972, and we don't
|
||||
know the history of earth's rotation accurately enough to map SI
|
||||
seconds to historical solar time to more than about one-hour
|
||||
accuracy. See: Morrison LV, Stephenson FR.
|
||||
Historical values of the Earth's clock error Delta T and the
|
||||
calculation of eclipses. J Hist Astron. 2004;35:327-36
|
||||
<http://adsabs.harvard.edu/full/2004JHA....35..327M>;
|
||||
@ -601,10 +614,14 @@ The tz code and data supply the following interfaces:
|
||||
|
||||
* The format of the country code file, documented in iso3166.tab.
|
||||
|
||||
When these interfaces are changed, an effort is made to preserve
|
||||
backward compatibility. For example, tz data files typically do not
|
||||
rely on recently-added zic features, so that users can run older zic
|
||||
versions to process newer data files.
|
||||
* The version number of the code and data, as the first line of
|
||||
the text file 'version' in each release.
|
||||
|
||||
Interface changes in a release attempt to preserve compatibility with
|
||||
recent releases. For example, tz data files typically do not rely on
|
||||
recently-added zic features, so that users can run older zic versions
|
||||
to process newer data files. The tz-link.htm file describes how
|
||||
releases are tagged and distributed.
|
||||
|
||||
Interfaces not listed above are less stable. For example, users
|
||||
should not rely on particular UT offsets or abbreviations for time
|
||||
|
@ -119,7 +119,7 @@ Zone Africa/Algiers 0:12:12 - LMT 1891 Mar 15 0:01
|
||||
# Cameroon
|
||||
# See Africa/Lagos.
|
||||
|
||||
# Cape Verde
|
||||
# Cape Verde / Cabo Verde
|
||||
#
|
||||
# Shanks gives 1907 for the transition to CVT.
|
||||
# Perhaps the 1911-05-26 Portuguese decree
|
||||
|
@ -1583,12 +1583,12 @@ Zone Asia/Amman 2:23:44 - LMT 1931
|
||||
# was "blended" with the Central zone. Therefore, Kazakhstan now has
|
||||
# two time zones, and difference between them is one hour. The zone
|
||||
# closer to UTC is the former Western zone (probably still called the
|
||||
# same), encompassing four provinces in the west: Aqtobe, Atyrau,
|
||||
# Mangghystau, and West Kazakhstan. The other zone encompasses
|
||||
# same), encompassing four provinces in the west: Aqtöbe, Atyraū,
|
||||
# Mangghystaū, and West Kazakhstan. The other zone encompasses
|
||||
# everything else.... I guess that would make Kazakhstan time zones
|
||||
# de jure UTC+5 and UTC+6 respectively.
|
||||
|
||||
# From Stepan Golosunov (2016-03-27) ([*] means see later comments below):
|
||||
# From Stepan Golosunov (2016-03-27):
|
||||
# Review of the linked documents from http://adilet.zan.kz/
|
||||
# produced the following data for post-1991 Kazakhstan:
|
||||
#
|
||||
@ -1634,7 +1634,7 @@ Zone Asia/Amman 2:23:44 - LMT 1931
|
||||
#
|
||||
# This implies that on 1991-03-31 Asia/Oral remained on +04/+05 while
|
||||
# the rest of Kazakhstan switched from +06/+07 to +05/06 or from +05/06
|
||||
# to +04/+05. It's unclear how Kzyl-Orda oblast moved into the fifth
|
||||
# to +04/+05. It's unclear how Qyzylorda oblast moved into the fifth
|
||||
# time belt. (By switching from +04/+05 to +05/+06 on 1991-09-29?) ...
|
||||
#
|
||||
# 1. Act of the Cabinet of Ministers of the Republic of Kazakhstan
|
||||
@ -1647,25 +1647,25 @@ Zone Asia/Amman 2:23:44 - LMT 1931
|
||||
# on the whole territory of Kazakhstan 1 hour forward on 1992-01-19 at
|
||||
# 2:00, specified DST rules. It acknowledged that Kazakhstan was
|
||||
# located in the fourth and the fifth time belts and specified the
|
||||
# border between them to be located east of Kustanay and Aktyubinsk
|
||||
# oblasts (notably including Turgai and Kzyl-Orda oblasts into the fifth
|
||||
# border between them to be located east of Qostanay and Aktyubinsk
|
||||
# oblasts (notably including Turgai and Qyzylorda oblasts into the fifth
|
||||
# time belt).
|
||||
#
|
||||
# This means switch on 1992-01-19 at 2:00 from +04/+05 to +05/+06 for
|
||||
# Asia/Aqtau, Asia/Aqtobe, Asia/Oral, Atyrau and Kustanay oblasts; from
|
||||
# +05/+06 to +06/+07 for Asia/Almaty and Asia/Qyzylorda (and Arkalyk) [*]....
|
||||
# Asia/Aqtau, Asia/Aqtobe, Asia/Oral, Atyraū and Qostanay oblasts; from
|
||||
# +05/+06 to +06/+07 for Asia/Almaty and Asia/Qyzylorda (and Arkalyk)....
|
||||
#
|
||||
# 2. Act of the Cabinet of Ministers of the Republic of Kazakhstan
|
||||
# from 1992-03-27 No. 284
|
||||
# http://adilet.zan.kz/rus/docs/P920000284_
|
||||
# cancels extra hour ("decree time") for Uralsk and Kzyl-Orda oblasts
|
||||
# cancels extra hour ("decree time") for Uralsk and Qyzylorda oblasts
|
||||
# since the last Sunday of March 1992, while keeping them in the fourth
|
||||
# and the fifth time belts respectively.
|
||||
#
|
||||
# 3. Order of the Prime Minister of the Republic of Kazakhstan
|
||||
# from 1994-09-23 No. 384
|
||||
# http://adilet.zan.kz/rus/docs/R940000384_
|
||||
# cancels the extra hour ("decree time") on the territory of Mangystau
|
||||
# cancels the extra hour ("decree time") on the territory of Mangghystaū
|
||||
# oblast since the last Sunday of September 1994 (saying that time on
|
||||
# the territory would correspond to the third time belt as a
|
||||
# result)....
|
||||
@ -1679,14 +1679,11 @@ Zone Asia/Amman 2:23:44 - LMT 1931
|
||||
# 5. Act of the Government of the Republic of Kazakhstan
|
||||
# from 1999-03-26 No. 305
|
||||
# http://adilet.zan.kz/rus/docs/P990000305_
|
||||
# cancels the extra hour ("decree time") for Atyrau oblast since the
|
||||
# cancels the extra hour ("decree time") for Atyraū oblast since the
|
||||
# last Sunday of March 1999 while retaining the oblast in the fourth
|
||||
# time belt.
|
||||
#
|
||||
# This means change from +05/+06 to +04/+05.
|
||||
#
|
||||
# There is no zone for Atyrau currently (listed under Asia/Aqtau in
|
||||
# zone1970.tab).[*]
|
||||
# This means change from +05/+06 to +04/+05....
|
||||
#
|
||||
# 6. Act of the Government of the Republic of Kazakhstan
|
||||
# from 2000-11-23 No. 1749
|
||||
@ -1696,10 +1693,10 @@ Zone Asia/Amman 2:23:44 - LMT 1931
|
||||
# The only changes I noticed are in definition of the border between the
|
||||
# fourth and the fifth time belts. They account for changes in spelling
|
||||
# and administrative division (splitting of Turgai oblast in 1997
|
||||
# probably changed time in territories incorporated into Kostanay oblast
|
||||
# (including Arkalyk) from +06/+07 to +05/+06) and move Kyzylorda oblast
|
||||
# probably changed time in territories incorporated into Qostanay oblast
|
||||
# (including Arkalyk) from +06/+07 to +05/+06) and move Qyzylorda oblast
|
||||
# from being in the fifth time belt and not using decree time into the
|
||||
# fourth time belt (no change in practice).[*]
|
||||
# fourth time belt (no change in practice).
|
||||
#
|
||||
# 7. Act of the Government of the Republic of Kazakhstan
|
||||
# from 2003-12-29 No. 1342
|
||||
@ -1709,7 +1706,7 @@ Zone Asia/Amman 2:23:44 - LMT 1931
|
||||
# 8. Act of the Government of the Republic of Kazakhstan
|
||||
# from 2004-07-20 No. 775
|
||||
# http://adilet.zan.kz/rus/archive/docs/P040000775_/20.07.2004
|
||||
# modified the 2000-11-23 act to move Kostanay and Kyzylorda oblasts into
|
||||
# modified the 2000-11-23 act to move Qostanay and Qyzylorda oblasts into
|
||||
# the fifth time belt and add Aktobe oblast to the list of regions not
|
||||
# using extra hour ("decree time"), leaving Kazakhstan with only 2 time
|
||||
# zones (+04/+05 and +06/+07). The changes were to be implemented
|
||||
@ -1721,14 +1718,14 @@ Zone Asia/Amman 2:23:44 - LMT 1931
|
||||
# http://adilet.zan.kz/rus/docs/P040001059_
|
||||
# modified the 2000-11-23 act to remove exceptions from the "decree time"
|
||||
# (leaving Kazakhstan in +05/+06 and +06/+07 zones), amended the
|
||||
# 2004-07-20 act to implement changes for Atyrau, West Kazakhstan,
|
||||
# Kostanay, Kyzylorda and Mangystau oblasts by not moving clocks
|
||||
# during the 2014 transition to "winter" time.
|
||||
# 2004-07-20 act to implement changes for Atyraū, West Kazakhstan,
|
||||
# Qostanay, Qyzylorda and Mangghystaū oblasts by not moving clocks
|
||||
# during the 2004 transition to "winter" time.
|
||||
#
|
||||
# This means transition from +04/+05 to +05/+06 for Atyrau oblast (no
|
||||
# This means transition from +04/+05 to +05/+06 for Atyraū oblast (no
|
||||
# zone currently), Asia/Oral, Asia/Aqtau and transition from +05/+06 to
|
||||
# +06/+07 for Kostanay oblast (Kostanay and Arkalyk, no zones currently)
|
||||
# and Asia/Qyzylorda on 2004-10-31 at 3:00....[*]
|
||||
# +06/+07 for Qostanay oblast (Qostanay and Arkalyk, no zones currently)
|
||||
# and Asia/Qyzylorda on 2004-10-31 at 3:00....
|
||||
#
|
||||
# 10. Act of the Government of the Republic of Kazakhstan
|
||||
# from 2005-03-15 No. 231
|
||||
@ -1744,14 +1741,9 @@ Zone Asia/Amman 2:23:44 - LMT 1931
|
||||
# Kazakh 1992-01-13 act appears to provide the same rules and 1992-03-27
|
||||
# act was to be enacted on the last Sunday of March 1992.
|
||||
|
||||
# From Paul Eggert (2016-04-15):
|
||||
# The tables below should reflect Stepan Golosunov's remarks above,
|
||||
# except for the items marked "[*]" which I haven't gotten to yet.
|
||||
# It looks like we will need new zones Asia/Atyrau and Asia/Qostanay
|
||||
# to handle changes from 1992 through 2004 that we did not previously
|
||||
# know about.
|
||||
# From Paul Eggert (2016-11-07):
|
||||
# The tables below reflect Golosunov's remarks, with exceptions as noted.
|
||||
|
||||
#
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
#
|
||||
# Almaty (formerly Alma-Ata), representing most locations in Kazakhstan
|
||||
@ -1764,6 +1756,8 @@ Zone Asia/Almaty 5:07:48 - LMT 1924 May 2 # or Alma-Ata
|
||||
6:00 RussiaAsia +06/+07 2004 Oct 31 2:00s
|
||||
6:00 - +06
|
||||
# Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.) (KZ-KZY)
|
||||
# This currently includes Qostanay (aka Kostanay, Kustanay) (KZ-KUS);
|
||||
# see comments below.
|
||||
Zone Asia/Qyzylorda 4:21:52 - LMT 1924 May 2
|
||||
4:00 - +04 1930 Jun 21
|
||||
5:00 - +05 1981 Apr 1
|
||||
@ -1775,7 +1769,21 @@ Zone Asia/Qyzylorda 4:21:52 - LMT 1924 May 2
|
||||
6:00 RussiaAsia +06/+07 1992 Mar 29 2:00s
|
||||
5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s
|
||||
6:00 - +06
|
||||
# Aqtobe (aka Aktobe, formerly Aktyubinsk) (KZ-AKT)
|
||||
# The following zone is like Asia/Qyzylorda except for being one
|
||||
# hour earlier from 1991-09-29 to 1992-03-29. The 1991/2 rules for
|
||||
# Qostenay are unclear partly because of the 1997 Turgai
|
||||
# reorganization, so this zone is commented out for now.
|
||||
#Zone Asia/Qostanay 4:14:20 - LMT 1924 May 2
|
||||
# 4:00 - +04 1930 Jun 21
|
||||
# 5:00 - +05 1981 Apr 1
|
||||
# 5:00 1:00 +06 1981 Oct 1
|
||||
# 6:00 - +06 1982 Apr 1
|
||||
# 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s
|
||||
# 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s
|
||||
# 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s
|
||||
# 6:00 - +06
|
||||
#
|
||||
# Aqtöbe (aka Aktobe, formerly Aktyubinsk) (KZ-AKT)
|
||||
Zone Asia/Aqtobe 3:48:40 - LMT 1924 May 2
|
||||
4:00 - +04 1930 Jun 21
|
||||
5:00 - +05 1981 Apr 1
|
||||
@ -1785,14 +1793,11 @@ Zone Asia/Aqtobe 3:48:40 - LMT 1924 May 2
|
||||
4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s
|
||||
5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s
|
||||
5:00 - +05
|
||||
# Qostanay (KZ-KUS)
|
||||
|
||||
# Mangghystau (KZ-MAN)
|
||||
# Mangghystaū (KZ-MAN)
|
||||
# Aqtau was not founded until 1963, but it represents an inhabited region,
|
||||
# so include time stamps before 1963.
|
||||
Zone Asia/Aqtau 3:21:04 - LMT 1924 May 2
|
||||
4:00 - +04 1930 Jun 21
|
||||
5:00 - +05 1963
|
||||
5:00 - +05 1981 Oct 1
|
||||
6:00 - +06 1982 Apr 1
|
||||
5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s
|
||||
@ -1800,7 +1805,17 @@ Zone Asia/Aqtau 3:21:04 - LMT 1924 May 2
|
||||
5:00 RussiaAsia +05/+06 1994 Sep 25 2:00s
|
||||
4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s
|
||||
5:00 - +05
|
||||
|
||||
# Atyraū (KZ-ATY) is like Mangghystaū except it switched from
|
||||
# +04/+05 to +05/+06 in spring 1999, not fall 1994.
|
||||
Zone Asia/Atyrau 3:27:44 - LMT 1924 May 2
|
||||
4:00 - +04 1930 Jun 21
|
||||
5:00 - +05 1981 Oct 1
|
||||
6:00 - +06 1982 Apr 1
|
||||
5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s
|
||||
4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s
|
||||
5:00 RussiaAsia +05/+06 1999 Mar 28 2:00s
|
||||
4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s
|
||||
5:00 - +05
|
||||
# West Kazakhstan (KZ-ZAP)
|
||||
# From Paul Eggert (2016-03-18):
|
||||
# The 1989 transition is from USSR act No. 227 (1989-03-14).
|
||||
@ -2616,7 +2631,7 @@ Rule Palestine 2016 max - Oct lastSat 1:00 0 -
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Asia/Gaza 2:17:52 - LMT 1900 Oct
|
||||
2:00 Zion EET 1948 May 15
|
||||
2:00 Zion EET/EEST 1948 May 15
|
||||
2:00 EgyptAsia EE%sT 1967 Jun 5
|
||||
2:00 Zion I%sT 1996
|
||||
2:00 Jordan EE%sT 1999
|
||||
@ -2629,7 +2644,7 @@ Zone Asia/Gaza 2:17:52 - LMT 1900 Oct
|
||||
2:00 Palestine EE%sT
|
||||
|
||||
Zone Asia/Hebron 2:20:23 - LMT 1900 Oct
|
||||
2:00 Zion EET 1948 May 15
|
||||
2:00 Zion EET/EEST 1948 May 15
|
||||
2:00 EgyptAsia EE%sT 1967 Jun 5
|
||||
2:00 Zion I%sT 1996
|
||||
2:00 Jordan EE%sT 1999
|
||||
|
@ -901,7 +901,7 @@ Zone Europe/Sofia 1:33:16 - LMT 1880
|
||||
# Cyprus
|
||||
# Please see the 'asia' file for Asia/Nicosia.
|
||||
|
||||
# Czech Republic
|
||||
# Czech Republic / Czechia
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule Czech 1945 only - Apr 8 2:00s 1:00 S
|
||||
Rule Czech 1945 only - Nov 18 2:00s 0 -
|
||||
@ -2601,10 +2601,9 @@ Zone Europe/Astrakhan 3:12:12 - LMT 1924 May
|
||||
3:00 - +03 2016 Mar 27 2:00s
|
||||
4:00 - +04
|
||||
|
||||
# From Paul Eggert (2016-03-18):
|
||||
# From Paul Eggert (2016-11-11):
|
||||
# Europe/Volgograd covers:
|
||||
# 34 RU-VGG Volgograd Oblast
|
||||
# 64 RU-SAR Saratov Oblast
|
||||
# The 1988 transition is from USSR act No. 5 (1988-01-04).
|
||||
|
||||
Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3
|
||||
@ -2617,6 +2616,27 @@ Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3
|
||||
4:00 - +04 2014 Oct 26 2:00s
|
||||
3:00 - +03
|
||||
|
||||
# From Paul Eggert (2016-11-11):
|
||||
# Europe/Saratov covers:
|
||||
# 64 RU-SAR Saratov Oblast
|
||||
|
||||
# From Yuri Konotopov (2016-11-11):
|
||||
# Dec 4, 2016 02:00 UTC+3.... Saratov Region's local time will be ... UTC+4.
|
||||
# From Stepan Golosunov (2016-11-11):
|
||||
# ... Byalokoz listed Saratov on 03:04:18.
|
||||
# From Stepan Golosunov (2016-11-22):
|
||||
# http://publication.pravo.gov.ru/Document/View/0001201611220031
|
||||
|
||||
Zone Europe/Saratov 3:04:18 - LMT 1919 Jul 1 0:00u
|
||||
3:00 - +03 1930 Jun 21
|
||||
4:00 Russia +04/+05 1988 Mar 27 2:00s
|
||||
3:00 Russia +03/+04 1991 Mar 31 2:00s
|
||||
4:00 - +04 1992 Mar 29 2:00s
|
||||
3:00 Russia +03/+04 2011 Mar 27 2:00s
|
||||
4:00 - +04 2014 Oct 26 2:00s
|
||||
3:00 - +03 2016 Dec 4 2:00s
|
||||
4:00 - +04
|
||||
|
||||
# From Paul Eggert (2016-03-18):
|
||||
# Europe/Kirov covers:
|
||||
# 43 RU-KIR Kirov Oblast
|
||||
|
@ -1 +1 @@
|
||||
2016i
|
||||
2016j
|
||||
|
@ -239,7 +239,8 @@ KY +1918-08123 America/Cayman
|
||||
KZ +4315+07657 Asia/Almaty Kazakhstan (most areas)
|
||||
KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda
|
||||
KZ +5017+05710 Asia/Aqtobe Aqtobe/Aktobe
|
||||
KZ +4431+05016 Asia/Aqtau Atyrau/Atirau/Gur'yev, Mangghystau/Mankistau
|
||||
KZ +4431+05016 Asia/Aqtau Mangghystau/Mankistau
|
||||
KZ +4707+05156 Asia/Atyrau Atyrau/Atirau/Gur'yev
|
||||
KZ +5113+05121 Asia/Oral West Kazakhstan
|
||||
LA +1758+10236 Asia/Vientiane
|
||||
LB +3353+03530 Asia/Beirut
|
||||
@ -330,14 +331,15 @@ RS +4450+02030 Europe/Belgrade
|
||||
RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad
|
||||
RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area
|
||||
RU +4457+03406 Europe/Simferopol MSK+00 - Crimea
|
||||
RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd, Saratov
|
||||
RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd
|
||||
RU +5836+04939 Europe/Kirov MSK+00 - Kirov
|
||||
RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan
|
||||
RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia
|
||||
RU +5134+04602 Europe/Saratov MSK+01 - Saratov
|
||||
RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk
|
||||
RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia
|
||||
RU +5651+06036 Asia/Yekaterinburg MSK+02 - Urals
|
||||
RU +5500+07324 Asia/Omsk MSK+03 - Omsk
|
||||
RU +5502+08255 Asia/Novosibirsk MSK+03 - Novosibirsk
|
||||
RU +5502+08255 Asia/Novosibirsk MSK+04 - Novosibirsk
|
||||
RU +5322+08345 Asia/Barnaul MSK+04 - Altai
|
||||
RU +5630+08458 Asia/Tomsk MSK+04 - Tomsk
|
||||
RU +5345+08707 Asia/Novokuznetsk MSK+04 - Kemerovo
|
||||
|
@ -211,8 +211,9 @@ KP +3901+12545 Asia/Pyongyang
|
||||
KR +3733+12658 Asia/Seoul
|
||||
KZ +4315+07657 Asia/Almaty Kazakhstan (most areas)
|
||||
KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda
|
||||
KZ +5017+05710 Asia/Aqtobe Aqtobe/Aktobe
|
||||
KZ +4431+05016 Asia/Aqtau Atyrau/Atirau/Gur'yev, Mangghystau/Mankistau
|
||||
KZ +5017+05710 Asia/Aqtobe Aqtöbe/Aktobe
|
||||
KZ +4431+05016 Asia/Aqtau Mangghystaū/Mankistau
|
||||
KZ +4707+05156 Asia/Atyrau Atyraū/Atirau/Gur'yev
|
||||
KZ +5113+05121 Asia/Oral West Kazakhstan
|
||||
LB +3353+03530 Asia/Beirut
|
||||
LK +0656+07951 Asia/Colombo
|
||||
@ -288,14 +289,15 @@ RS,BA,HR,ME,MK,SI +4450+02030 Europe/Belgrade
|
||||
RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad
|
||||
RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area
|
||||
RU +4457+03406 Europe/Simferopol MSK+00 - Crimea
|
||||
RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd, Saratov
|
||||
RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd
|
||||
RU +5836+04939 Europe/Kirov MSK+00 - Kirov
|
||||
RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan
|
||||
RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia
|
||||
RU +5134+04602 Europe/Saratov MSK+01 - Saratov
|
||||
RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk
|
||||
RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia
|
||||
RU +5651+06036 Asia/Yekaterinburg MSK+02 - Urals
|
||||
RU +5500+07324 Asia/Omsk MSK+03 - Omsk
|
||||
RU +5502+08255 Asia/Novosibirsk MSK+03 - Novosibirsk
|
||||
RU +5502+08255 Asia/Novosibirsk MSK+04 - Novosibirsk
|
||||
RU +5322+08345 Asia/Barnaul MSK+04 - Altai
|
||||
RU +5630+08458 Asia/Tomsk MSK+04 - Tomsk
|
||||
RU +5345+08707 Asia/Novokuznetsk MSK+04 - Kemerovo
|
||||
|
@ -120,6 +120,9 @@ pccard_ether_restart()
|
||||
pccard_ether_startchildren()
|
||||
{
|
||||
for child in `get_if_var $ifn wlans_IF`; do
|
||||
if ifexists $child; then
|
||||
continue
|
||||
fi
|
||||
/etc/rc.d/netif quietstart $child
|
||||
done
|
||||
}
|
||||
|
@ -7,6 +7,9 @@ INTERNALLIB=
|
||||
|
||||
SRCDIR= lib
|
||||
SRCS+= Support/APInt.cpp
|
||||
.if ${MACHINE_ARCH:Mpowerpc*} != ""
|
||||
SRCS+= Support/Atomic.cpp
|
||||
.endif
|
||||
SRCS+= Support/CommandLine.cpp
|
||||
SRCS+= Support/ConvertUTF.c
|
||||
SRCS+= Support/ConvertUTFWrapper.cpp
|
||||
|
@ -72,6 +72,7 @@ TESTS_SRCS= \
|
||||
test_compat_mac.c \
|
||||
test_compat_pax_libarchive_2x.c \
|
||||
test_compat_perl_archive_tar.c \
|
||||
test_compat_plexus_archiver_tar.c \
|
||||
test_compat_solaris_tar_acl.c \
|
||||
test_compat_solaris_pax_sparse.c \
|
||||
test_compat_star_acl_posix1e.c \
|
||||
@ -350,6 +351,7 @@ ${PACKAGE}FILES+= test_compat_mac-1.tar.Z.uu
|
||||
${PACKAGE}FILES+= test_compat_mac-2.tar.Z.uu
|
||||
${PACKAGE}FILES+= test_compat_pax_libarchive_2x.tar.Z.uu
|
||||
${PACKAGE}FILES+= test_compat_perl_archive_tar.tar.uu
|
||||
${PACKAGE}FILES+= test_compat_plexus_archiver_tar.tar.uu
|
||||
${PACKAGE}FILES+= test_compat_solaris_pax_sparse_1.pax.Z.uu
|
||||
${PACKAGE}FILES+= test_compat_solaris_pax_sparse_2.pax.Z.uu
|
||||
${PACKAGE}FILES+= test_compat_solaris_tar_acl.tar.uu
|
||||
|
@ -14,11 +14,14 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rand48.h"
|
||||
|
||||
long
|
||||
jrand48(unsigned short xseed[3])
|
||||
{
|
||||
|
||||
_dorand48(xseed);
|
||||
return ((long) xseed[2] << 16) + (long) xseed[1];
|
||||
return ((int32_t)(((uint32_t)xseed[2] << 16) | (uint32_t)xseed[1]));
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rand48.h"
|
||||
|
||||
extern unsigned short _rand48_seed[3];
|
||||
@ -21,6 +23,8 @@ extern unsigned short _rand48_seed[3];
|
||||
long
|
||||
mrand48(void)
|
||||
{
|
||||
|
||||
_dorand48(_rand48_seed);
|
||||
return ((long) _rand48_seed[2] << 16) + (long) _rand48_seed[1];
|
||||
return ((int32_t)(((uint32_t)_rand48_seed[2] << 16) |
|
||||
(uint32_t)_rand48_seed[1]));
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -122,31 +123,46 @@ char *
|
||||
link_ntoa(const struct sockaddr_dl *sdl)
|
||||
{
|
||||
static char obuf[64];
|
||||
char *out = obuf;
|
||||
int i;
|
||||
u_char *in = (u_char *)LLADDR(sdl);
|
||||
u_char *inlim = in + sdl->sdl_alen;
|
||||
int firsttime = 1;
|
||||
_Static_assert(sizeof(obuf) >= IFNAMSIZ + 20, "obuf is too small");
|
||||
char *out;
|
||||
const u_char *in, *inlim;
|
||||
int namelen, i, rem;
|
||||
|
||||
if (sdl->sdl_nlen) {
|
||||
bcopy(sdl->sdl_data, obuf, sdl->sdl_nlen);
|
||||
out += sdl->sdl_nlen;
|
||||
if (sdl->sdl_alen)
|
||||
namelen = (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ;
|
||||
|
||||
out = obuf;
|
||||
rem = sizeof(obuf);
|
||||
if (namelen > 0) {
|
||||
bcopy(sdl->sdl_data, out, namelen);
|
||||
out += namelen;
|
||||
rem -= namelen;
|
||||
if (sdl->sdl_alen > 0) {
|
||||
*out++ = ':';
|
||||
rem--;
|
||||
}
|
||||
while (in < inlim) {
|
||||
if (firsttime)
|
||||
firsttime = 0;
|
||||
else
|
||||
}
|
||||
|
||||
in = (const u_char *)sdl->sdl_data + sdl->sdl_nlen;
|
||||
inlim = in + sdl->sdl_alen;
|
||||
|
||||
while (in < inlim && rem > 1) {
|
||||
if (in != (const u_char *)sdl->sdl_data + sdl->sdl_nlen) {
|
||||
*out++ = '.';
|
||||
rem--;
|
||||
}
|
||||
i = *in++;
|
||||
if (i > 0xf) {
|
||||
out[1] = hexlist[i & 0xf];
|
||||
i >>= 4;
|
||||
out[0] = hexlist[i];
|
||||
out += 2;
|
||||
} else
|
||||
if (rem < 3)
|
||||
break;
|
||||
*out++ = hexlist[i >> 4];
|
||||
*out++ = hexlist[i & 0xf];
|
||||
rem -= 2;
|
||||
} else {
|
||||
if (rem < 2)
|
||||
break;
|
||||
*out++ = hexlist[i];
|
||||
rem--;
|
||||
}
|
||||
}
|
||||
*out = 0;
|
||||
return (obuf);
|
||||
|
@ -797,7 +797,7 @@ sctp_sendmsgx(int sd,
|
||||
memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
|
||||
sinfo.sinfo_ppid = ppid;
|
||||
sinfo.sinfo_flags = flags;
|
||||
sinfo.sinfo_ssn = stream_no;
|
||||
sinfo.sinfo_stream = stream_no;
|
||||
sinfo.sinfo_timetolive = timetolive;
|
||||
sinfo.sinfo_context = context;
|
||||
return (sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0));
|
||||
|
@ -176,7 +176,7 @@ sdump_group(struct group *grp, char *buffer, size_t buflen)
|
||||
char **cp;
|
||||
int written;
|
||||
|
||||
written = snprintf(buffer, buflen, "%s %s %d",
|
||||
written = snprintf(buffer, buflen, "%s:%s:%d:",
|
||||
grp->gr_name, grp->gr_passwd, grp->gr_gid);
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
@ -186,7 +186,8 @@ sdump_group(struct group *grp, char *buffer, size_t buflen)
|
||||
if (grp->gr_mem != NULL) {
|
||||
if (*(grp->gr_mem) != '\0') {
|
||||
for (cp = grp->gr_mem; *cp; ++cp) {
|
||||
written = snprintf(buffer, buflen, " %s",*cp);
|
||||
written = snprintf(buffer, buflen, "%s%s",
|
||||
cp == grp->gr_mem ? "" : ",", *cp);
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
@ -206,6 +207,7 @@ group_read_snapshot_func(struct group *grp, char *line)
|
||||
{
|
||||
StringList *sl;
|
||||
char *s, *ps, *ts;
|
||||
const char *sep;
|
||||
int i;
|
||||
|
||||
printf("1 line read from snapshot:\n%s\n", line);
|
||||
@ -213,8 +215,9 @@ group_read_snapshot_func(struct group *grp, char *line)
|
||||
i = 0;
|
||||
sl = NULL;
|
||||
ps = line;
|
||||
sep = ":";
|
||||
memset(grp, 0, sizeof(struct group));
|
||||
while ((s = strsep(&ps, " ")) != NULL) {
|
||||
while ((s = strsep(&ps, sep)) != NULL) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
grp->gr_name = strdup(s);
|
||||
@ -235,6 +238,8 @@ group_read_snapshot_func(struct group *grp, char *line)
|
||||
grp->gr_passwd = NULL;
|
||||
return (-1);
|
||||
}
|
||||
/* Change to parsing groups. */
|
||||
sep = ",";
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -335,7 +335,6 @@ fetch_connect(const char *host, int port, int af, int verbose)
|
||||
fetch_info("resolving server address: %s:%d", host, port);
|
||||
if ((sais = fetch_resolve(host, port, af)) == NULL)
|
||||
goto fail;
|
||||
fetch_info("resolved");
|
||||
|
||||
/* resolve client address */
|
||||
bindaddr = getenv("FETCH_BIND_ADDRESS");
|
||||
|
@ -426,8 +426,6 @@ nopgrp:
|
||||
kp->ki_pri.pri_native = mtd.td_base_pri;
|
||||
kp->ki_lastcpu = mtd.td_lastcpu;
|
||||
kp->ki_wchan = mtd.td_wchan;
|
||||
if (mtd.td_name[0] != 0)
|
||||
strlcpy(kp->ki_tdname, mtd.td_name, MAXCOMLEN);
|
||||
kp->ki_oncpu = mtd.td_oncpu;
|
||||
if (mtd.td_name[0] != '\0')
|
||||
strlcpy(kp->ki_tdname, mtd.td_name, sizeof(kp->ki_tdname));
|
||||
|
@ -5,7 +5,8 @@
|
||||
PACKAGE=lib${LIB}
|
||||
LIB= proc
|
||||
|
||||
SRCS= proc_bkpt.c \
|
||||
SRCS= crc32.c \
|
||||
proc_bkpt.c \
|
||||
proc_create.c \
|
||||
proc_regs.c \
|
||||
proc_sym.c \
|
||||
@ -36,7 +37,7 @@ CFLAGS+= -I${.CURDIR}/../../cddl/contrib/opensolaris/lib/libctf/common \
|
||||
CFLAGS+= -DNO_CTF
|
||||
.endif
|
||||
|
||||
SHLIB_MAJOR= 3
|
||||
SHLIB_MAJOR= 4
|
||||
|
||||
MAN=
|
||||
|
||||
|
@ -26,29 +26,56 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef __LIBPROC_H_
|
||||
#define __LIBPROC_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
#include <libelf.h>
|
||||
#include <rtld_db.h>
|
||||
|
||||
#include "libproc.h"
|
||||
|
||||
struct procstat;
|
||||
|
||||
struct symtab {
|
||||
Elf_Data *data;
|
||||
u_int nsyms;
|
||||
u_int *index;
|
||||
u_long stridx;
|
||||
};
|
||||
|
||||
struct file_info {
|
||||
Elf *elf;
|
||||
int fd;
|
||||
u_int refs;
|
||||
GElf_Ehdr ehdr;
|
||||
|
||||
/* Symbol tables, sorted by value. */
|
||||
struct symtab dynsymtab;
|
||||
struct symtab symtab;
|
||||
};
|
||||
|
||||
struct map_info {
|
||||
prmap_t map;
|
||||
struct file_info *file;
|
||||
};
|
||||
|
||||
struct proc_handle {
|
||||
pid_t pid; /* Process ID. */
|
||||
struct proc_handle_public public; /* Public fields. */
|
||||
int flags; /* Process flags. */
|
||||
int status; /* Process status (PS_*). */
|
||||
int wstat; /* Process wait status. */
|
||||
int model; /* Process data model. */
|
||||
rd_agent_t *rdap; /* librtld_db agent */
|
||||
rd_loadobj_t *rdobjs; /* Array of loaded objects. */
|
||||
size_t rdobjsz; /* Array size. */
|
||||
size_t nobjs; /* Num. objects currently loaded. */
|
||||
rd_loadobj_t *rdexec; /* rdobj for program executable. */
|
||||
struct lwpstatus lwps; /* Process status. */
|
||||
struct map_info *mappings; /* File mappings for proc. */
|
||||
size_t maparrsz; /* Map array size. */
|
||||
size_t nmappings; /* Number of mappings. */
|
||||
prmap_t *exec_map; /* Executable text mapping. */
|
||||
lwpstatus_t lwps; /* Process status. */
|
||||
struct procstat *procstat; /* libprocstat handle. */
|
||||
char execpath[MAXPATHLEN]; /* Path to program executable. */
|
||||
char execpath[PATH_MAX]; /* Path to program executable. */
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -58,3 +85,5 @@ struct proc_handle {
|
||||
#define DPRINTF(...) do { } while (0)
|
||||
#define DPRINTFX(...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif /* __LIBPROC_H_ */
|
||||
|
57
lib/libproc/crc32.c
Normal file
57
lib/libproc/crc32.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*-
|
||||
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
|
||||
* code or tables extracted from it, as desired without restriction.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <crc32.h>
|
||||
|
||||
uint32_t crc32_tab[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
28
lib/libproc/crc32.h
Normal file
28
lib/libproc/crc32.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*-
|
||||
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
|
||||
* code or tables extracted from it, as desired without restriction.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _CRC32_H_
|
||||
#define _CRC32_H_
|
||||
|
||||
#include <stdint.h> /* uint32_t */
|
||||
#include <stdlib.h> /* size_t */
|
||||
|
||||
extern uint32_t crc32_tab[];
|
||||
|
||||
static __inline uint32_t
|
||||
crc32(const void *buf, size_t size)
|
||||
{
|
||||
const uint8_t *p = buf;
|
||||
uint32_t crc;
|
||||
|
||||
crc = ~0U;
|
||||
while (size--)
|
||||
crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
|
||||
return (crc ^ ~0U);
|
||||
}
|
||||
|
||||
#endif /* !_CRC32_H_ */
|
@ -50,6 +50,11 @@ typedef void (*proc_child_func)(void *);
|
||||
#define PS_DEAD 5
|
||||
#define PS_LOST 6
|
||||
|
||||
/* Flags for proc_attach(). */
|
||||
#define PATTACH_FORCE 0x01
|
||||
#define PATTACH_RDONLY 0x02
|
||||
#define PATTACH_NOSTOP 0x04
|
||||
|
||||
/* Reason values for proc_detach(). */
|
||||
#define PRELEASE_HANG 1
|
||||
#define PRELEASE_KILL 2
|
||||
@ -116,13 +121,18 @@ typedef struct lwpstatus {
|
||||
#define PR_MODEL_ILP32 1
|
||||
#define PR_MODEL_LP64 2
|
||||
|
||||
struct proc_handle_public {
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
#define proc_getpid(phdl) (((struct proc_handle_public *)(phdl))->pid)
|
||||
|
||||
/* Function prototype definitions. */
|
||||
__BEGIN_DECLS
|
||||
|
||||
prmap_t *proc_addr2map(struct proc_handle *, uintptr_t);
|
||||
prmap_t *proc_name2map(struct proc_handle *, const char *);
|
||||
char *proc_objname(struct proc_handle *, uintptr_t, char *, size_t);
|
||||
prmap_t *proc_obj2map(struct proc_handle *, const char *);
|
||||
int proc_iter_objs(struct proc_handle *, proc_map_f *, void *);
|
||||
int proc_iter_symbyaddr(struct proc_handle *, const char *, int,
|
||||
int, proc_sym_f *, void *);
|
||||
@ -140,7 +150,6 @@ struct ctf_file *proc_name2ctf(struct proc_handle *, const char *);
|
||||
int proc_setflags(struct proc_handle *, int);
|
||||
int proc_state(struct proc_handle *);
|
||||
int proc_getmodel(struct proc_handle *);
|
||||
pid_t proc_getpid(struct proc_handle *);
|
||||
int proc_wstatus(struct proc_handle *);
|
||||
int proc_getwstat(struct proc_handle *);
|
||||
char * proc_signame(int, char *, size_t);
|
||||
@ -158,4 +167,4 @@ int proc_regset(struct proc_handle *, proc_reg_t, unsigned long);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* !_LIBPROC_H_ */
|
||||
#endif /* _LIBPROC_H_ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*-
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -33,13 +33,13 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <machine/_inttypes.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "_libproc.h"
|
||||
|
||||
#if defined(__aarch64__)
|
||||
@ -130,8 +130,8 @@ proc_bkptset(struct proc_handle *phdl, uintptr_t address,
|
||||
piod.piod_addr = &instr;
|
||||
piod.piod_len = BREAKPOINT_INSTR_SZ;
|
||||
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
|
||||
DPRINTF("ERROR: couldn't read instruction at address 0x%"
|
||||
PRIuPTR, address);
|
||||
DPRINTF("ERROR: couldn't read instruction at address 0x%jx",
|
||||
(uintmax_t)address);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
@ -146,8 +146,8 @@ proc_bkptset(struct proc_handle *phdl, uintptr_t address,
|
||||
piod.piod_addr = &instr;
|
||||
piod.piod_len = BREAKPOINT_INSTR_SZ;
|
||||
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
|
||||
DPRINTF("ERROR: couldn't write instruction at address 0x%"
|
||||
PRIuPTR, address);
|
||||
DPRINTF("ERROR: couldn't write instruction at address 0x%jx",
|
||||
(uintmax_t)address);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
@ -194,8 +194,8 @@ proc_bkptdel(struct proc_handle *phdl, uintptr_t address,
|
||||
piod.piod_addr = &instr;
|
||||
piod.piod_len = BREAKPOINT_INSTR_SZ;
|
||||
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
|
||||
DPRINTF("ERROR: couldn't write instruction at address 0x%"
|
||||
PRIuPTR, address);
|
||||
DPRINTF("ERROR: couldn't write instruction at address 0x%jx",
|
||||
(uintmax_t)address);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
|
@ -22,10 +22,11 @@
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
@ -78,7 +79,7 @@ proc_init(pid_t pid, int flags, int status, struct proc_handle **pphdl)
|
||||
goto out;
|
||||
|
||||
memset(phdl, 0, sizeof(*phdl));
|
||||
phdl->pid = pid;
|
||||
phdl->public.pid = pid;
|
||||
phdl->flags = flags;
|
||||
phdl->status = status;
|
||||
phdl->procstat = procstat_open_sysctl();
|
||||
@ -126,7 +127,7 @@ proc_attach(pid_t pid, int flags, struct proc_handle **pphdl)
|
||||
struct proc_handle *phdl;
|
||||
int error, status;
|
||||
|
||||
if (pid == 0 || pid == getpid())
|
||||
if (pid == 0 || (pid == getpid() && (flags & PATTACH_RDONLY) == 0))
|
||||
return (EINVAL);
|
||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||
return (ENOENT);
|
||||
@ -139,7 +140,8 @@ proc_attach(pid_t pid, int flags, struct proc_handle **pphdl)
|
||||
if (error != 0)
|
||||
goto out;
|
||||
|
||||
if (ptrace(PT_ATTACH, phdl->pid, 0, 0) != 0) {
|
||||
if ((flags & PATTACH_RDONLY) == 0) {
|
||||
if (ptrace(PT_ATTACH, proc_getpid(phdl), 0, 0) != 0) {
|
||||
error = errno;
|
||||
DPRINTF("ERROR: cannot ptrace child process %d", pid);
|
||||
goto out;
|
||||
@ -158,8 +160,12 @@ proc_attach(pid_t pid, int flags, struct proc_handle **pphdl)
|
||||
else
|
||||
phdl->status = PS_STOP;
|
||||
|
||||
if ((flags & PATTACH_NOSTOP) != 0)
|
||||
proc_continue(phdl);
|
||||
}
|
||||
|
||||
out:
|
||||
if (error && phdl != NULL) {
|
||||
if (error != 0 && phdl != NULL) {
|
||||
proc_free(phdl);
|
||||
phdl = NULL;
|
||||
}
|
||||
@ -229,8 +235,28 @@ bad:
|
||||
void
|
||||
proc_free(struct proc_handle *phdl)
|
||||
{
|
||||
struct file_info *file;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < phdl->nmappings; i++) {
|
||||
file = phdl->mappings[i].file;
|
||||
if (file != NULL && --file->refs == 0) {
|
||||
if (file->elf != NULL) {
|
||||
(void)elf_end(file->elf);
|
||||
(void)close(file->fd);
|
||||
if (file->symtab.nsyms > 0)
|
||||
free(file->symtab.index);
|
||||
if (file->dynsymtab.nsyms > 0)
|
||||
free(file->dynsymtab.index);
|
||||
}
|
||||
free(file);
|
||||
}
|
||||
}
|
||||
if (phdl->maparrsz > 0)
|
||||
free(phdl->mappings);
|
||||
if (phdl->procstat != NULL)
|
||||
procstat_close(phdl->procstat);
|
||||
if (phdl->rdap != NULL)
|
||||
rd_delete(phdl->rdap);
|
||||
free(phdl);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*-
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "_libproc.h"
|
||||
|
||||
int
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*-
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -31,46 +31,99 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtld_db.h>
|
||||
#include "libproc.h"
|
||||
|
||||
#include "_libproc.h"
|
||||
|
||||
static void rdl2prmap(const rd_loadobj_t *, prmap_t *);
|
||||
|
||||
static int
|
||||
map_iter(const rd_loadobj_t *lop, void *arg)
|
||||
{
|
||||
struct proc_handle *phdl = arg;
|
||||
struct file_info *file;
|
||||
struct map_info *mapping, *tmp;
|
||||
struct proc_handle *phdl;
|
||||
size_t i;
|
||||
|
||||
if (phdl->nobjs >= phdl->rdobjsz) {
|
||||
phdl->rdobjsz *= 2;
|
||||
phdl->rdobjs = reallocf(phdl->rdobjs, sizeof(*phdl->rdobjs) *
|
||||
phdl->rdobjsz);
|
||||
if (phdl->rdobjs == NULL)
|
||||
phdl = arg;
|
||||
if (phdl->nmappings >= phdl->maparrsz) {
|
||||
phdl->maparrsz *= 2;
|
||||
tmp = reallocarray(phdl->mappings, phdl->maparrsz,
|
||||
sizeof(*phdl->mappings));
|
||||
if (tmp == NULL)
|
||||
return (-1);
|
||||
phdl->mappings = tmp;
|
||||
}
|
||||
|
||||
mapping = &phdl->mappings[phdl->nmappings];
|
||||
rdl2prmap(lop, &mapping->map);
|
||||
if (strcmp(lop->rdl_path, phdl->execpath) == 0 &&
|
||||
(lop->rdl_prot & RD_RDL_X) != 0)
|
||||
phdl->rdexec = &phdl->rdobjs[phdl->nobjs];
|
||||
memcpy(&phdl->rdobjs[phdl->nobjs++], lop, sizeof(*lop));
|
||||
phdl->exec_map = &mapping->map;
|
||||
|
||||
file = NULL;
|
||||
if (lop->rdl_path[0] != '\0') {
|
||||
/* Look for an existing mapping of the same file. */
|
||||
for (i = 0; i < phdl->nmappings; i++)
|
||||
if (strcmp(mapping->map.pr_mapname,
|
||||
phdl->mappings[i].map.pr_mapname) == 0) {
|
||||
file = phdl->mappings[i].file;
|
||||
break;
|
||||
}
|
||||
|
||||
if (file == NULL) {
|
||||
file = malloc(sizeof(*file));
|
||||
if (file == NULL)
|
||||
return (-1);
|
||||
file->elf = NULL;
|
||||
file->fd = -1;
|
||||
file->refs = 1;
|
||||
} else
|
||||
file->refs++;
|
||||
}
|
||||
mapping->file = file;
|
||||
phdl->nmappings++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
rdl2prmap(const rd_loadobj_t *rdl, prmap_t *map)
|
||||
{
|
||||
|
||||
map->pr_vaddr = rdl->rdl_saddr;
|
||||
map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr;
|
||||
map->pr_offset = rdl->rdl_offset;
|
||||
map->pr_mflags = 0;
|
||||
if (rdl->rdl_prot & RD_RDL_R)
|
||||
map->pr_mflags |= MA_READ;
|
||||
if (rdl->rdl_prot & RD_RDL_W)
|
||||
map->pr_mflags |= MA_WRITE;
|
||||
if (rdl->rdl_prot & RD_RDL_X)
|
||||
map->pr_mflags |= MA_EXEC;
|
||||
(void)strlcpy(map->pr_mapname, rdl->rdl_path,
|
||||
sizeof(map->pr_mapname));
|
||||
}
|
||||
|
||||
rd_agent_t *
|
||||
proc_rdagent(struct proc_handle *phdl)
|
||||
{
|
||||
|
||||
if (phdl->rdap == NULL && phdl->status != PS_UNDEAD &&
|
||||
phdl->status != PS_IDLE) {
|
||||
if ((phdl->rdap = rd_new(phdl)) != NULL) {
|
||||
phdl->rdobjs = malloc(sizeof(*phdl->rdobjs) * 64);
|
||||
phdl->rdobjsz = 64;
|
||||
if (phdl->rdobjs == NULL)
|
||||
return (phdl->rdap);
|
||||
rd_loadobj_iter(phdl->rdap, map_iter, phdl);
|
||||
}
|
||||
}
|
||||
if ((phdl->rdap = rd_new(phdl)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
phdl->maparrsz = 64;
|
||||
phdl->mappings = calloc(phdl->maparrsz,
|
||||
sizeof(*phdl->mappings));
|
||||
if (phdl->mappings == NULL)
|
||||
return (phdl->rdap);
|
||||
if (rd_loadobj_iter(phdl->rdap, map_iter, phdl) != RD_OK)
|
||||
return (NULL);
|
||||
}
|
||||
return (phdl->rdap);
|
||||
}
|
||||
|
||||
@ -78,7 +131,6 @@ void
|
||||
proc_updatesyms(struct proc_handle *phdl)
|
||||
{
|
||||
|
||||
memset(phdl->rdobjs, 0, sizeof(*phdl->rdobjs) * phdl->rdobjsz);
|
||||
phdl->nobjs = 0;
|
||||
memset(phdl->mappings, 0, sizeof(*phdl->mappings) * phdl->maparrsz);
|
||||
rd_loadobj_iter(phdl->rdap, map_iter, phdl);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Mark Johnston <markj@FreeBSD.org>
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* Copyright (c) 2008 John Birrell (jb@freebsd.org)
|
||||
* All rights reserved.
|
||||
@ -51,8 +52,11 @@ __FBSDID("$FreeBSD$");
|
||||
#endif
|
||||
#include <libutil.h>
|
||||
|
||||
#include "crc32.h"
|
||||
#include "_libproc.h"
|
||||
|
||||
#define PATH_DEBUG_DIR "/usr/lib/debug"
|
||||
|
||||
#ifdef NO_CTF
|
||||
typedef struct ctf_file ctf_file_t;
|
||||
#endif
|
||||
@ -61,7 +65,21 @@ typedef struct ctf_file ctf_file_t;
|
||||
extern char *__cxa_demangle(const char *, char *, size_t *, int *);
|
||||
#endif /* NO_CXA_DEMANGLE */
|
||||
|
||||
static void proc_rdl2prmap(rd_loadobj_t *, prmap_t *);
|
||||
static int
|
||||
crc32_file(int fd, uint32_t *crc)
|
||||
{
|
||||
uint8_t buf[PAGE_SIZE], *p;
|
||||
size_t n;
|
||||
|
||||
*crc = ~0;
|
||||
while ((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||
p = &buf[0];
|
||||
while (n-- > 0)
|
||||
*crc = crc32_tab[(*crc ^ *p++) & 0xff] ^ (*crc >> 8);
|
||||
}
|
||||
*crc = ~*crc;
|
||||
return (n);
|
||||
}
|
||||
|
||||
static void
|
||||
demangle(const char *symbol, char *buf, size_t len)
|
||||
@ -83,341 +101,427 @@ fail:
|
||||
}
|
||||
|
||||
static int
|
||||
find_dbg_obj(const char *path)
|
||||
symvalcomp(void *thunk, const void *a1, const void *a2)
|
||||
{
|
||||
int fd;
|
||||
char dbg_path[PATH_MAX];
|
||||
struct symtab *symtab;
|
||||
GElf_Sym sym1, sym2;
|
||||
u_int i1, i2;
|
||||
int ret;
|
||||
|
||||
snprintf(dbg_path, sizeof(dbg_path),
|
||||
"/usr/lib/debug/%s.debug", path);
|
||||
fd = open(dbg_path, O_RDONLY);
|
||||
if (fd >= 0)
|
||||
return (fd);
|
||||
i1 = *(const u_int *)a1;
|
||||
i2 = *(const u_int *)a2;
|
||||
symtab = thunk;
|
||||
|
||||
(void)gelf_getsym(symtab->data, i1, &sym1);
|
||||
(void)gelf_getsym(symtab->data, i2, &sym2);
|
||||
if (sym1.st_value < sym2.st_value)
|
||||
ret = -1;
|
||||
else if (sym1.st_value == sym2.st_value)
|
||||
ret = 0;
|
||||
else
|
||||
return (open(path, O_RDONLY));
|
||||
ret = 1;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
load_symtab(Elf *e, struct symtab *symtab, u_long sh_type)
|
||||
{
|
||||
GElf_Ehdr ehdr;
|
||||
GElf_Shdr shdr;
|
||||
Elf_Scn *scn;
|
||||
u_int nsyms;
|
||||
|
||||
if (gelf_getehdr(e, &ehdr) == NULL)
|
||||
return (-1);
|
||||
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
(void)gelf_getshdr(scn, &shdr);
|
||||
if (shdr.sh_type == sh_type)
|
||||
break;
|
||||
}
|
||||
if (scn == NULL)
|
||||
return (-1);
|
||||
|
||||
if ((symtab->data = elf_getdata(scn, NULL)) == NULL)
|
||||
return (-1);
|
||||
|
||||
nsyms = shdr.sh_size / shdr.sh_entsize;
|
||||
|
||||
symtab->index = calloc(nsyms, sizeof(u_int));
|
||||
if (symtab->index == NULL)
|
||||
return (-1);
|
||||
for (u_int i = 0; i < nsyms; i++)
|
||||
symtab->index[i] = i;
|
||||
qsort_r(symtab->index, nsyms, sizeof(u_int), symtab, symvalcomp);
|
||||
symtab->nsyms = nsyms;
|
||||
symtab->stridx = shdr.sh_link;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map)
|
||||
load_symtabs(struct file_info *file)
|
||||
{
|
||||
map->pr_vaddr = rdl->rdl_saddr;
|
||||
map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr;
|
||||
map->pr_offset = rdl->rdl_offset;
|
||||
map->pr_mflags = 0;
|
||||
if (rdl->rdl_prot & RD_RDL_R)
|
||||
map->pr_mflags |= MA_READ;
|
||||
if (rdl->rdl_prot & RD_RDL_W)
|
||||
map->pr_mflags |= MA_WRITE;
|
||||
if (rdl->rdl_prot & RD_RDL_X)
|
||||
map->pr_mflags |= MA_EXEC;
|
||||
strlcpy(map->pr_mapname, rdl->rdl_path,
|
||||
sizeof(map->pr_mapname));
|
||||
|
||||
file->symtab.nsyms = file->dynsymtab.nsyms = 0;
|
||||
(void)load_symtab(file->elf, &file->symtab, SHT_SYMTAB);
|
||||
(void)load_symtab(file->elf, &file->dynsymtab, SHT_DYNSYM);
|
||||
}
|
||||
|
||||
static int
|
||||
open_debug_file(char *path, const char *debugfile, uint32_t crc)
|
||||
{
|
||||
size_t n;
|
||||
uint32_t compcrc;
|
||||
int fd;
|
||||
|
||||
fd = -1;
|
||||
if ((n = strlcat(path, "/", PATH_MAX)) >= PATH_MAX)
|
||||
return (fd);
|
||||
if (strlcat(path, debugfile, PATH_MAX) >= PATH_MAX)
|
||||
goto out;
|
||||
if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0)
|
||||
goto out;
|
||||
if (crc32_file(fd, &compcrc) != 0 || crc != compcrc) {
|
||||
DPRINTFX("ERROR: CRC32 mismatch for %s", path);
|
||||
(void)close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
out:
|
||||
path[n] = '\0';
|
||||
return (fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain an ELF descriptor for the specified mapped object. If a GNU debuglink
|
||||
* section is present, a descriptor for the corresponding debug file is
|
||||
* returned.
|
||||
*/
|
||||
static int
|
||||
open_object(struct map_info *mapping)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
GElf_Shdr shdr;
|
||||
Elf *e, *e2;
|
||||
Elf_Data *data;
|
||||
Elf_Scn *scn;
|
||||
struct file_info *file;
|
||||
prmap_t *map;
|
||||
const char *debugfile, *scnname;
|
||||
size_t ndx;
|
||||
uint32_t crc;
|
||||
int fd, fd2;
|
||||
|
||||
if (mapping->map.pr_mapname[0] == '\0')
|
||||
return (-1); /* anonymous object */
|
||||
if (mapping->file->elf != NULL)
|
||||
return (0); /* already loaded */
|
||||
|
||||
file = mapping->file;
|
||||
map = &mapping->map;
|
||||
if ((fd = open(map->pr_mapname, O_RDONLY | O_CLOEXEC)) < 0) {
|
||||
DPRINTF("ERROR: open %s failed", map->pr_mapname);
|
||||
return (-1);
|
||||
}
|
||||
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
|
||||
DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
|
||||
goto err;
|
||||
}
|
||||
if (gelf_getehdr(e, &file->ehdr) != &file->ehdr) {
|
||||
DPRINTFX("ERROR: elf_getehdr() failed: %s", elf_errmsg(-1));
|
||||
goto err;
|
||||
}
|
||||
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
||||
DPRINTFX("ERROR: gelf_getshdr failed: %s",
|
||||
elf_errmsg(-1));
|
||||
goto err;
|
||||
}
|
||||
if (shdr.sh_type != SHT_PROGBITS)
|
||||
continue;
|
||||
if (elf_getshdrstrndx(e, &ndx) != 0) {
|
||||
DPRINTFX("ERROR: elf_getshdrstrndx failed: %s",
|
||||
elf_errmsg(-1));
|
||||
goto err;
|
||||
}
|
||||
if ((scnname = elf_strptr(e, ndx, shdr.sh_name)) == NULL)
|
||||
continue;
|
||||
|
||||
if (strcmp(scnname, ".gnu_debuglink") == 0)
|
||||
break;
|
||||
}
|
||||
if (scn == NULL)
|
||||
goto internal;
|
||||
|
||||
if ((data = elf_getdata(scn, NULL)) == NULL) {
|
||||
DPRINTFX("ERROR: elf_getdata failed: %s", elf_errmsg(-1));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* The data contains a null-terminated file name followed by a 4-byte
|
||||
* CRC.
|
||||
*/
|
||||
if (data->d_size < sizeof(crc) + 1) {
|
||||
DPRINTFX("ERROR: debuglink section is too small (%zd bytes)",
|
||||
data->d_size);
|
||||
goto internal;
|
||||
}
|
||||
if (strnlen(data->d_buf, data->d_size) >= data->d_size - sizeof(crc)) {
|
||||
DPRINTFX("ERROR: no null-terminator in gnu_debuglink section");
|
||||
goto internal;
|
||||
}
|
||||
|
||||
debugfile = data->d_buf;
|
||||
memcpy(&crc, (char *)data->d_buf + data->d_size - sizeof(crc),
|
||||
sizeof(crc));
|
||||
|
||||
/*
|
||||
* Search for the debug file using the algorithm described in the gdb
|
||||
* documentation:
|
||||
* - look in the directory containing the object,
|
||||
* - look in the subdirectory ".debug" of the directory containing the
|
||||
* object,
|
||||
* - look in the global debug directories (currently /usr/lib/debug).
|
||||
*/
|
||||
(void)strlcpy(path, map->pr_mapname, sizeof(path));
|
||||
(void)dirname(path);
|
||||
|
||||
if ((fd2 = open_debug_file(path, debugfile, crc)) >= 0)
|
||||
goto external;
|
||||
|
||||
if (strlcat(path, "/.debug", sizeof(path)) < sizeof(path) &&
|
||||
(fd2 = open_debug_file(path, debugfile, crc)) >= 0)
|
||||
goto external;
|
||||
|
||||
(void)snprintf(path, sizeof(path), PATH_DEBUG_DIR);
|
||||
if (strlcat(path, map->pr_mapname, sizeof(path)) < sizeof(path)) {
|
||||
(void)dirname(path);
|
||||
if ((fd2 = open_debug_file(path, debugfile, crc)) >= 0)
|
||||
goto external;
|
||||
}
|
||||
|
||||
internal:
|
||||
/* We didn't find a debug file, just return the object's descriptor. */
|
||||
file->elf = e;
|
||||
file->fd = fd;
|
||||
load_symtabs(file);
|
||||
return (0);
|
||||
|
||||
external:
|
||||
if ((e2 = elf_begin(fd2, ELF_C_READ, NULL)) == NULL) {
|
||||
DPRINTFX("ERROR: elf_begin failed: %s", elf_errmsg(-1));
|
||||
(void)close(fd2);
|
||||
goto err;
|
||||
}
|
||||
(void)elf_end(e);
|
||||
(void)close(fd);
|
||||
file->elf = e2;
|
||||
file->fd = fd2;
|
||||
load_symtabs(file);
|
||||
return (0);
|
||||
|
||||
err:
|
||||
if (e != NULL)
|
||||
(void)elf_end(e);
|
||||
(void)close(fd);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
char *
|
||||
proc_objname(struct proc_handle *p, uintptr_t addr, char *objname,
|
||||
size_t objnamesz)
|
||||
{
|
||||
prmap_t *map;
|
||||
size_t i;
|
||||
rd_loadobj_t *rdl;
|
||||
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
|
||||
strlcpy(objname, rdl->rdl_path, objnamesz);
|
||||
for (i = 0; i < p->nmappings; i++) {
|
||||
map = &p->mappings[i].map;
|
||||
if (addr >= map->pr_vaddr &&
|
||||
addr < map->pr_vaddr + map->pr_size) {
|
||||
strlcpy(objname, map->pr_mapname, objnamesz);
|
||||
return (objname);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
prmap_t *
|
||||
proc_obj2map(struct proc_handle *p, const char *objname)
|
||||
{
|
||||
size_t i;
|
||||
prmap_t *map;
|
||||
rd_loadobj_t *rdl;
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
rdl = NULL;
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
basename_r(p->rdobjs[i].rdl_path, path);
|
||||
if (strcmp(path, objname) == 0) {
|
||||
rdl = &p->rdobjs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rdl == NULL) {
|
||||
if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL)
|
||||
rdl = p->rdexec;
|
||||
else
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((map = malloc(sizeof(*map))) == NULL)
|
||||
return (NULL);
|
||||
proc_rdl2prmap(rdl, map);
|
||||
return (map);
|
||||
}
|
||||
|
||||
int
|
||||
proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd)
|
||||
{
|
||||
char last[MAXPATHLEN], path[MAXPATHLEN], *base;
|
||||
prmap_t *map;
|
||||
size_t i;
|
||||
rd_loadobj_t *rdl;
|
||||
prmap_t map;
|
||||
char path[MAXPATHLEN];
|
||||
char last[MAXPATHLEN];
|
||||
int error;
|
||||
|
||||
if (p->nobjs == 0)
|
||||
if (p->nmappings == 0)
|
||||
if (proc_rdagent(p) == NULL)
|
||||
return (-1);
|
||||
|
||||
error = 0;
|
||||
memset(last, 0, sizeof(last));
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
proc_rdl2prmap(rdl, &map);
|
||||
basename_r(rdl->rdl_path, path);
|
||||
for (i = 0; i < p->nmappings; i++) {
|
||||
map = &p->mappings[i].map;
|
||||
strlcpy(path, map->pr_mapname, sizeof(path));
|
||||
base = basename(path);
|
||||
/*
|
||||
* We shouldn't call the callback twice with the same object.
|
||||
* To do that we are assuming the fact that if there are
|
||||
* repeated object names (i.e. different mappings for the
|
||||
* same object) they occur next to each other.
|
||||
*/
|
||||
if (strcmp(path, last) == 0)
|
||||
if (strcmp(base, last) == 0)
|
||||
continue;
|
||||
if ((error = (*func)(cd, &map, path)) != 0)
|
||||
if ((error = (*func)(cd, map, base)) != 0)
|
||||
break;
|
||||
strlcpy(last, path, sizeof(last));
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
static struct map_info *
|
||||
_proc_addr2map(struct proc_handle *p, uintptr_t addr)
|
||||
{
|
||||
struct map_info *mapping;
|
||||
size_t i;
|
||||
|
||||
if (p->nmappings == 0)
|
||||
if (proc_rdagent(p) == NULL)
|
||||
return (NULL);
|
||||
for (i = 0; i < p->nmappings; i++) {
|
||||
mapping = &p->mappings[i];
|
||||
if (addr >= mapping->map.pr_vaddr &&
|
||||
addr < mapping->map.pr_vaddr + mapping->map.pr_size)
|
||||
return (mapping);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
prmap_t *
|
||||
proc_addr2map(struct proc_handle *p, uintptr_t addr)
|
||||
{
|
||||
size_t i;
|
||||
int cnt, lastvn = 0;
|
||||
prmap_t *map;
|
||||
rd_loadobj_t *rdl;
|
||||
struct kinfo_vmentry *kves, *kve;
|
||||
|
||||
/*
|
||||
* If we don't have a cache of listed objects, we need to query
|
||||
* it ourselves.
|
||||
*/
|
||||
if (p->nobjs == 0) {
|
||||
if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL)
|
||||
return (NULL);
|
||||
for (i = 0; i < (size_t)cnt; i++) {
|
||||
kve = kves + i;
|
||||
if (kve->kve_type == KVME_TYPE_VNODE)
|
||||
lastvn = i;
|
||||
if (addr >= kve->kve_start && addr < kve->kve_end) {
|
||||
if ((map = malloc(sizeof(*map))) == NULL) {
|
||||
free(kves);
|
||||
return (NULL);
|
||||
}
|
||||
map->pr_vaddr = kve->kve_start;
|
||||
map->pr_size = kve->kve_end - kve->kve_start;
|
||||
map->pr_offset = kve->kve_offset;
|
||||
map->pr_mflags = 0;
|
||||
if (kve->kve_protection & KVME_PROT_READ)
|
||||
map->pr_mflags |= MA_READ;
|
||||
if (kve->kve_protection & KVME_PROT_WRITE)
|
||||
map->pr_mflags |= MA_WRITE;
|
||||
if (kve->kve_protection & KVME_PROT_EXEC)
|
||||
map->pr_mflags |= MA_EXEC;
|
||||
if (kve->kve_flags & KVME_FLAG_COW)
|
||||
map->pr_mflags |= MA_COW;
|
||||
if (kve->kve_flags & KVME_FLAG_NEEDS_COPY)
|
||||
map->pr_mflags |= MA_NEEDS_COPY;
|
||||
if (kve->kve_flags & KVME_FLAG_NOCOREDUMP)
|
||||
map->pr_mflags |= MA_NOCOREDUMP;
|
||||
strlcpy(map->pr_mapname, kves[lastvn].kve_path,
|
||||
sizeof(map->pr_mapname));
|
||||
free(kves);
|
||||
return (map);
|
||||
}
|
||||
}
|
||||
free(kves);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
|
||||
if ((map = malloc(sizeof(*map))) == NULL)
|
||||
return (NULL);
|
||||
proc_rdl2prmap(rdl, map);
|
||||
return (map);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
return (&_proc_addr2map(p, addr)->map);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the symbol at addr, returning a copy of the symbol and its name.
|
||||
* Look up the symbol at addr using a binary search, returning a copy of the
|
||||
* symbol and its name.
|
||||
*/
|
||||
static int
|
||||
lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr,
|
||||
const char **name, GElf_Sym *symcopy)
|
||||
lookup_symbol_by_addr(Elf *elf, struct symtab *symtab, uintptr_t addr,
|
||||
const char **namep, GElf_Sym *sym)
|
||||
{
|
||||
GElf_Sym sym;
|
||||
Elf_Data *data;
|
||||
const char *s;
|
||||
uint64_t rsym;
|
||||
int i;
|
||||
int min, max, mid;
|
||||
|
||||
if ((data = elf_getdata(scn, NULL)) == NULL) {
|
||||
DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
|
||||
return (1);
|
||||
}
|
||||
for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
|
||||
rsym = off + sym.st_value;
|
||||
if (addr >= rsym && addr < rsym + sym.st_size) {
|
||||
s = elf_strptr(e, stridx, sym.st_name);
|
||||
if (s != NULL) {
|
||||
*name = s;
|
||||
memcpy(symcopy, &sym, sizeof(*symcopy));
|
||||
/*
|
||||
* DTrace expects the st_value to contain
|
||||
* only the address relative to the start of
|
||||
* the function.
|
||||
*/
|
||||
symcopy->st_value = rsym;
|
||||
data = symtab->data;
|
||||
min = 0;
|
||||
max = symtab->nsyms - 1;
|
||||
|
||||
while (min <= max) {
|
||||
mid = (max + min) / 2;
|
||||
(void)gelf_getsym(data, symtab->index[mid], sym);
|
||||
if (addr >= sym->st_value &&
|
||||
addr < sym->st_value + sym->st_size) {
|
||||
s = elf_strptr(elf, symtab->stridx, sym->st_name);
|
||||
if (s != NULL && namep != NULL)
|
||||
*namep = s;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (addr < sym->st_value)
|
||||
max = mid - 1;
|
||||
else
|
||||
min = mid + 1;
|
||||
}
|
||||
}
|
||||
return (1);
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
int
|
||||
proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
|
||||
size_t namesz, GElf_Sym *symcopy)
|
||||
{
|
||||
GElf_Ehdr ehdr;
|
||||
GElf_Shdr shdr;
|
||||
Elf *e;
|
||||
Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
|
||||
prmap_t *map;
|
||||
struct file_info *file;
|
||||
struct map_info *mapping;
|
||||
const char *s;
|
||||
uintptr_t off;
|
||||
u_long symtabstridx = 0, dynsymstridx = 0;
|
||||
int fd, error = -1;
|
||||
int error;
|
||||
|
||||
if ((map = proc_addr2map(p, addr)) == NULL)
|
||||
if ((mapping = _proc_addr2map(p, addr)) == NULL) {
|
||||
DPRINTFX("ERROR: proc_addr2map failed to resolve 0x%jx", addr);
|
||||
return (-1);
|
||||
if ((fd = find_dbg_obj(map->pr_mapname)) < 0) {
|
||||
DPRINTF("ERROR: open %s failed", map->pr_mapname);
|
||||
goto err0;
|
||||
}
|
||||
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
|
||||
DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
|
||||
goto err1;
|
||||
}
|
||||
if (gelf_getehdr(e, &ehdr) == NULL) {
|
||||
DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
|
||||
goto err2;
|
||||
if (open_object(mapping) != 0) {
|
||||
DPRINTFX("ERROR: failed to open object %s",
|
||||
mapping->map.pr_mapname);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the index of the STRTAB and SYMTAB sections to locate
|
||||
* symbol names.
|
||||
*/
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
gelf_getshdr(scn, &shdr);
|
||||
switch (shdr.sh_type) {
|
||||
case SHT_SYMTAB:
|
||||
symtabscn = scn;
|
||||
symtabstridx = shdr.sh_link;
|
||||
break;
|
||||
case SHT_DYNSYM:
|
||||
dynsymscn = scn;
|
||||
dynsymstridx = shdr.sh_link;
|
||||
break;
|
||||
}
|
||||
}
|
||||
file = mapping->file;
|
||||
off = file->ehdr.e_type == ET_DYN ? mapping->map.pr_vaddr : 0;
|
||||
if (addr < off)
|
||||
return (ENOENT);
|
||||
addr -= off;
|
||||
|
||||
off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
|
||||
|
||||
/*
|
||||
* First look up the symbol in the dynsymtab, and fall back to the
|
||||
* symtab if the lookup fails.
|
||||
*/
|
||||
error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy);
|
||||
if (error == 0)
|
||||
goto out;
|
||||
|
||||
error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy);
|
||||
if (error != 0)
|
||||
goto err2;
|
||||
|
||||
out:
|
||||
error = lookup_symbol_by_addr(file->elf, &file->dynsymtab, addr, &s,
|
||||
symcopy);
|
||||
if (error == ENOENT)
|
||||
error = lookup_symbol_by_addr(file->elf, &file->symtab, addr,
|
||||
&s, symcopy);
|
||||
if (error == 0) {
|
||||
symcopy->st_value += off;
|
||||
demangle(s, name, namesz);
|
||||
err2:
|
||||
elf_end(e);
|
||||
err1:
|
||||
close(fd);
|
||||
err0:
|
||||
free(map);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
static struct map_info *
|
||||
_proc_name2map(struct proc_handle *p, const char *name)
|
||||
{
|
||||
char path[MAXPATHLEN], *base;
|
||||
struct map_info *mapping;
|
||||
size_t i, len;
|
||||
|
||||
if ((len = strlen(name)) == 0)
|
||||
return (NULL);
|
||||
if (p->nmappings == 0)
|
||||
if (proc_rdagent(p) == NULL)
|
||||
return (NULL);
|
||||
for (i = 0; i < p->nmappings; i++) {
|
||||
mapping = &p->mappings[i];
|
||||
(void)strlcpy(path, mapping->map.pr_mapname, sizeof(path));
|
||||
base = basename(path);
|
||||
if (strcmp(base, name) == 0)
|
||||
return (mapping);
|
||||
}
|
||||
/* If we didn't find a match, try matching prefixes of the basename. */
|
||||
for (i = 0; i < p->nmappings; i++) {
|
||||
strlcpy(path, p->mappings[i].map.pr_mapname, sizeof(path));
|
||||
base = basename(path);
|
||||
if (strncmp(base, name, len) == 0)
|
||||
return (&p->mappings[i]);
|
||||
}
|
||||
if (strcmp(name, "a.out") == 0)
|
||||
return (_proc_addr2map(p, p->exec_map->pr_vaddr));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
prmap_t *
|
||||
proc_name2map(struct proc_handle *p, const char *name)
|
||||
{
|
||||
size_t i;
|
||||
int cnt;
|
||||
prmap_t *map = NULL;
|
||||
char tmppath[MAXPATHLEN];
|
||||
struct kinfo_vmentry *kves, *kve;
|
||||
rd_loadobj_t *rdl;
|
||||
|
||||
/*
|
||||
* If we haven't iterated over the list of loaded objects,
|
||||
* librtld_db isn't yet initialized and it's very likely
|
||||
* that librtld_db called us. We need to do the heavy
|
||||
* lifting here to find the symbol librtld_db is looking for.
|
||||
*/
|
||||
if (p->nobjs == 0) {
|
||||
if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL)
|
||||
return (NULL);
|
||||
for (i = 0; i < (size_t)cnt; i++) {
|
||||
kve = kves + i;
|
||||
basename_r(kve->kve_path, tmppath);
|
||||
if (strcmp(tmppath, name) == 0) {
|
||||
map = proc_addr2map(p, kve->kve_start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(kves);
|
||||
} else
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
basename_r(rdl->rdl_path, tmppath);
|
||||
if (strcmp(tmppath, name) == 0) {
|
||||
if ((map = malloc(sizeof(*map))) == NULL)
|
||||
return (NULL);
|
||||
proc_rdl2prmap(rdl, map);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (map == NULL && strcmp(name, "a.out") == 0 && p->rdexec != NULL)
|
||||
map = proc_addr2map(p, p->rdexec->rdl_saddr);
|
||||
|
||||
return (map);
|
||||
return (&_proc_name2map(p, name)->map);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the symbol with the given name and return a copy of it.
|
||||
*/
|
||||
static int
|
||||
lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol,
|
||||
lookup_symbol_by_name(Elf *elf, struct symtab *symtab, const char *symbol,
|
||||
GElf_Sym *symcopy, prsyminfo_t *si)
|
||||
{
|
||||
GElf_Sym sym;
|
||||
@ -425,12 +529,11 @@ lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol,
|
||||
char *s;
|
||||
int i;
|
||||
|
||||
if ((data = elf_getdata(scn, NULL)) == NULL) {
|
||||
DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
|
||||
return (1);
|
||||
}
|
||||
if (symtab->nsyms == 0)
|
||||
return (ENOENT);
|
||||
data = symtab->data;
|
||||
for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
|
||||
s = elf_strptr(e, stridx, sym.st_name);
|
||||
s = elf_strptr(elf, symtab->stridx, sym.st_name);
|
||||
if (s != NULL && strcmp(s, symbol) == 0) {
|
||||
memcpy(symcopy, &sym, sizeof(*symcopy));
|
||||
if (si != NULL)
|
||||
@ -438,80 +541,38 @@ lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol,
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return (1);
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
int
|
||||
proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
|
||||
GElf_Sym *symcopy, prsyminfo_t *si)
|
||||
{
|
||||
Elf *e;
|
||||
Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
|
||||
GElf_Shdr shdr;
|
||||
GElf_Ehdr ehdr;
|
||||
prmap_t *map;
|
||||
struct file_info *file;
|
||||
struct map_info *mapping;
|
||||
uintptr_t off;
|
||||
u_long symtabstridx = 0, dynsymstridx = 0;
|
||||
int fd, error = -1;
|
||||
int error;
|
||||
|
||||
if ((map = proc_name2map(p, object)) == NULL) {
|
||||
DPRINTFX("ERROR: couldn't find object %s", object);
|
||||
goto err0;
|
||||
}
|
||||
if ((fd = find_dbg_obj(map->pr_mapname)) < 0) {
|
||||
DPRINTF("ERROR: open %s failed", map->pr_mapname);
|
||||
goto err0;
|
||||
}
|
||||
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
|
||||
DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
|
||||
goto err1;
|
||||
}
|
||||
if (gelf_getehdr(e, &ehdr) == NULL) {
|
||||
DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
|
||||
goto err2;
|
||||
}
|
||||
/*
|
||||
* Find the index of the STRTAB and SYMTAB sections to locate
|
||||
* symbol names.
|
||||
*/
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
gelf_getshdr(scn, &shdr);
|
||||
switch (shdr.sh_type) {
|
||||
case SHT_SYMTAB:
|
||||
symtabscn = scn;
|
||||
symtabstridx = shdr.sh_link;
|
||||
break;
|
||||
case SHT_DYNSYM:
|
||||
dynsymscn = scn;
|
||||
dynsymstridx = shdr.sh_link;
|
||||
break;
|
||||
if ((mapping = _proc_name2map(p, object)) == NULL) {
|
||||
DPRINTFX("ERROR: proc_name2map failed to resolve %s", object);
|
||||
return (-1);
|
||||
}
|
||||
if (open_object(mapping) != 0) {
|
||||
DPRINTFX("ERROR: failed to open object %s",
|
||||
mapping->map.pr_mapname);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* First look up the symbol in the dynsymtab, and fall back to the
|
||||
* symtab if the lookup fails.
|
||||
*/
|
||||
error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy, si);
|
||||
file = mapping->file;
|
||||
off = file->ehdr.e_type == ET_DYN ? mapping->map.pr_vaddr : 0;
|
||||
|
||||
error = lookup_symbol_by_name(file->elf, &file->dynsymtab, symbol,
|
||||
symcopy, si);
|
||||
if (error == ENOENT)
|
||||
error = lookup_symbol_by_name(file->elf, &file->symtab, symbol,
|
||||
symcopy, si);
|
||||
if (error == 0)
|
||||
goto out;
|
||||
|
||||
error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy, si);
|
||||
if (error == 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
|
||||
symcopy->st_value += off;
|
||||
|
||||
err2:
|
||||
elf_end(e);
|
||||
err1:
|
||||
close(fd);
|
||||
err0:
|
||||
free(map);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -527,7 +588,6 @@ proc_name2ctf(struct proc_handle *p, const char *name)
|
||||
return (NULL);
|
||||
|
||||
ctf = ctf_open(map->pr_mapname, &error);
|
||||
free(map);
|
||||
return (ctf);
|
||||
#else
|
||||
(void)p;
|
||||
@ -540,56 +600,30 @@ int
|
||||
proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
|
||||
int mask, proc_sym_f *func, void *cd)
|
||||
{
|
||||
Elf *e;
|
||||
int i, fd;
|
||||
prmap_t *map;
|
||||
Elf_Scn *scn, *foundscn = NULL;
|
||||
Elf_Data *data;
|
||||
GElf_Ehdr ehdr;
|
||||
GElf_Shdr shdr;
|
||||
GElf_Sym sym;
|
||||
unsigned long stridx = -1;
|
||||
char *s;
|
||||
int error = -1;
|
||||
struct file_info *file;
|
||||
struct map_info *mapping;
|
||||
struct symtab *symtab;
|
||||
const char *s;
|
||||
int error, i;
|
||||
|
||||
if ((map = proc_name2map(p, object)) == NULL)
|
||||
if ((mapping = _proc_name2map(p, object)) == NULL) {
|
||||
DPRINTFX("ERROR: proc_name2map failed to resolve %s", object);
|
||||
return (-1);
|
||||
if ((fd = find_dbg_obj(map->pr_mapname)) < 0) {
|
||||
DPRINTF("ERROR: open %s failed", map->pr_mapname);
|
||||
goto err0;
|
||||
}
|
||||
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
|
||||
DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
|
||||
goto err1;
|
||||
}
|
||||
if (gelf_getehdr(e, &ehdr) == NULL) {
|
||||
DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
|
||||
goto err2;
|
||||
}
|
||||
/*
|
||||
* Find the section we are looking for.
|
||||
*/
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
gelf_getshdr(scn, &shdr);
|
||||
if (which == PR_SYMTAB &&
|
||||
shdr.sh_type == SHT_SYMTAB) {
|
||||
foundscn = scn;
|
||||
break;
|
||||
} else if (which == PR_DYNSYM &&
|
||||
shdr.sh_type == SHT_DYNSYM) {
|
||||
foundscn = scn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundscn)
|
||||
if (open_object(mapping) != 0) {
|
||||
DPRINTFX("ERROR: failed to open object %s",
|
||||
mapping->map.pr_mapname);
|
||||
return (-1);
|
||||
stridx = shdr.sh_link;
|
||||
if ((data = elf_getdata(foundscn, NULL)) == NULL) {
|
||||
DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
|
||||
goto err2;
|
||||
}
|
||||
for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
|
||||
|
||||
file = mapping->file;
|
||||
symtab = which == PR_SYMTAB ? &file->symtab : &file->dynsymtab;
|
||||
if (symtab->nsyms == 0)
|
||||
return (-1);
|
||||
|
||||
error = 0;
|
||||
for (i = 0; gelf_getsym(symtab->data, i, &sym) != NULL; i++) {
|
||||
if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
|
||||
(mask & BIND_LOCAL) == 0)
|
||||
continue;
|
||||
@ -614,18 +648,11 @@ proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
|
||||
if (GELF_ST_TYPE(sym.st_info) == STT_FILE &&
|
||||
(mask & TYPE_FILE) == 0)
|
||||
continue;
|
||||
s = elf_strptr(e, stridx, sym.st_name);
|
||||
if (ehdr.e_type != ET_EXEC)
|
||||
sym.st_value += map->pr_vaddr;
|
||||
s = elf_strptr(file->elf, symtab->stridx, sym.st_name);
|
||||
if (file->ehdr.e_type == ET_DYN)
|
||||
sym.st_value += mapping->map.pr_vaddr;
|
||||
if ((error = (*func)(cd, &sym, s)) != 0)
|
||||
goto err2;
|
||||
break;
|
||||
}
|
||||
error = 0;
|
||||
err2:
|
||||
elf_end(e);
|
||||
err1:
|
||||
close(fd);
|
||||
err0:
|
||||
free(map);
|
||||
return (error);
|
||||
}
|
||||
|
@ -26,18 +26,21 @@
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "_libproc.h"
|
||||
|
||||
int
|
||||
@ -58,14 +61,17 @@ proc_clearflags(struct proc_handle *phdl, int mask)
|
||||
int
|
||||
proc_continue(struct proc_handle *phdl)
|
||||
{
|
||||
int pending = 0;
|
||||
int pending;
|
||||
|
||||
if (phdl == NULL)
|
||||
return (-1);
|
||||
|
||||
if (phdl->status == PS_STOP && WSTOPSIG(phdl->wstat) != SIGTRAP)
|
||||
pending = WSTOPSIG(phdl->wstat);
|
||||
if (ptrace(PT_CONTINUE, phdl->pid, (caddr_t)(uintptr_t)1, pending) != 0)
|
||||
else
|
||||
pending = 0;
|
||||
if (ptrace(PT_CONTINUE, proc_getpid(phdl), (caddr_t)(uintptr_t)1,
|
||||
pending) != 0)
|
||||
return (-1);
|
||||
|
||||
phdl->status = PS_RUN;
|
||||
@ -77,23 +83,29 @@ int
|
||||
proc_detach(struct proc_handle *phdl, int reason)
|
||||
{
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
if (phdl == NULL)
|
||||
return (EINVAL);
|
||||
if (reason == PRELEASE_HANG)
|
||||
return (EINVAL);
|
||||
if (reason == PRELEASE_KILL) {
|
||||
kill(phdl->pid, SIGKILL);
|
||||
return (0);
|
||||
kill(proc_getpid(phdl), SIGKILL);
|
||||
goto free;
|
||||
}
|
||||
if (ptrace(PT_DETACH, phdl->pid, 0, 0) != 0 && errno == ESRCH)
|
||||
return (0);
|
||||
if ((phdl->flags & PATTACH_RDONLY) != 0)
|
||||
goto free;
|
||||
pid = proc_getpid(phdl);
|
||||
if (ptrace(PT_DETACH, pid, 0, 0) != 0 && errno == ESRCH)
|
||||
goto free;
|
||||
if (errno == EBUSY) {
|
||||
kill(phdl->pid, SIGSTOP);
|
||||
waitpid(phdl->pid, &status, WUNTRACED);
|
||||
ptrace(PT_DETACH, phdl->pid, 0, 0);
|
||||
kill(phdl->pid, SIGCONT);
|
||||
return (0);
|
||||
kill(pid, SIGSTOP);
|
||||
waitpid(pid, &status, WUNTRACED);
|
||||
ptrace(PT_DETACH, pid, 0, 0);
|
||||
kill(pid, SIGCONT);
|
||||
}
|
||||
|
||||
free:
|
||||
proc_free(phdl);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -129,16 +141,6 @@ proc_state(struct proc_handle *phdl)
|
||||
return (phdl->status);
|
||||
}
|
||||
|
||||
pid_t
|
||||
proc_getpid(struct proc_handle *phdl)
|
||||
{
|
||||
|
||||
if (phdl == NULL)
|
||||
return (-1);
|
||||
|
||||
return (phdl->pid);
|
||||
}
|
||||
|
||||
int
|
||||
proc_getmodel(struct proc_handle *phdl)
|
||||
{
|
||||
@ -156,7 +158,7 @@ proc_wstatus(struct proc_handle *phdl)
|
||||
|
||||
if (phdl == NULL)
|
||||
return (-1);
|
||||
if (waitpid(phdl->pid, &status, WUNTRACED) < 0) {
|
||||
if (waitpid(proc_getpid(phdl), &status, WUNTRACED) < 0) {
|
||||
if (errno != EINTR)
|
||||
DPRINTF("waitpid");
|
||||
return (-1);
|
||||
@ -201,7 +203,7 @@ proc_read(struct proc_handle *phdl, void *buf, size_t size, size_t addr)
|
||||
piod.piod_addr = (void *)buf;
|
||||
piod.piod_offs = (void *)addr;
|
||||
|
||||
if (ptrace(PT_IO, phdl->pid, (caddr_t)&piod, 0) < 0)
|
||||
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0)
|
||||
return (-1);
|
||||
return (piod.piod_len);
|
||||
}
|
||||
@ -215,7 +217,7 @@ proc_getlwpstatus(struct proc_handle *phdl)
|
||||
|
||||
if (phdl == NULL)
|
||||
return (NULL);
|
||||
if (ptrace(PT_LWPINFO, phdl->pid, (caddr_t)&lwpinfo,
|
||||
if (ptrace(PT_LWPINFO, proc_getpid(phdl), (caddr_t)&lwpinfo,
|
||||
sizeof(lwpinfo)) < 0)
|
||||
return (NULL);
|
||||
siginfo = &lwpinfo.pl_siginfo;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2014, 2015 Mark Johnston <markj@FreeBSD.org>
|
||||
* Copyright (c) 2014-2016 Mark Johnston <markj@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -152,38 +152,6 @@ verify_bkpt(struct proc_handle *phdl, GElf_Sym *sym, const char *symname,
|
||||
"expected map name '%s' doesn't match '%s'", mapname, mapbname);
|
||||
}
|
||||
|
||||
ATF_TC(map_alias_obj2map);
|
||||
ATF_TC_HEAD(map_alias_obj2map, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr",
|
||||
"Callers are supposed to be able to use \"a.out\" as an alias for "
|
||||
"the program executable. Make sure that proc_obj2map() handles "
|
||||
"this properly.");
|
||||
}
|
||||
ATF_TC_BODY(map_alias_obj2map, tc)
|
||||
{
|
||||
struct proc_handle *phdl;
|
||||
prmap_t *map1, *map2;
|
||||
|
||||
phdl = start_prog(tc, false);
|
||||
|
||||
/* Initialize the rtld_db handle. */
|
||||
(void)proc_rdagent(phdl);
|
||||
|
||||
/* Ensure that "target_prog" and "a.out" return the same map. */
|
||||
map1 = proc_obj2map(phdl, target_prog_file);
|
||||
ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for '%s'",
|
||||
target_prog_file);
|
||||
map2 = proc_obj2map(phdl, aout_object);
|
||||
ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for '%s'",
|
||||
aout_object);
|
||||
ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0);
|
||||
|
||||
ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
|
||||
|
||||
proc_free(phdl);
|
||||
}
|
||||
|
||||
ATF_TC(map_alias_name2map);
|
||||
ATF_TC_HEAD(map_alias_name2map, tc)
|
||||
{
|
||||
@ -216,6 +184,35 @@ ATF_TC_BODY(map_alias_name2map, tc)
|
||||
proc_free(phdl);
|
||||
}
|
||||
|
||||
ATF_TC(map_prefix_name2map);
|
||||
ATF_TC_HEAD(map_prefix_name2map, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr",
|
||||
"Verify that proc_name2map() returns prefix matches of the "
|
||||
"basename of loaded objects if no full matches are found.");
|
||||
}
|
||||
ATF_TC_BODY(map_prefix_name2map, tc)
|
||||
{
|
||||
struct proc_handle *phdl;
|
||||
prmap_t *map1, *map2;
|
||||
|
||||
phdl = start_prog(tc, false);
|
||||
|
||||
/* Initialize the rtld_db handle. */
|
||||
(void)proc_rdagent(phdl);
|
||||
|
||||
/* Make sure that "ld-elf" and "ld-elf.so" return the same map. */
|
||||
map1 = proc_name2map(phdl, "ld-elf");
|
||||
ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for 'ld-elf'");
|
||||
map2 = proc_name2map(phdl, "ld-elf.so");
|
||||
ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for 'ld-elf.so'");
|
||||
ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0);
|
||||
|
||||
ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
|
||||
|
||||
proc_free(phdl);
|
||||
}
|
||||
|
||||
ATF_TC(map_alias_name2sym);
|
||||
ATF_TC_HEAD(map_alias_name2sym, tc)
|
||||
{
|
||||
@ -315,7 +312,7 @@ ATF_TC_BODY(symbol_lookup_fail, tc)
|
||||
/* Initialize the rtld_db handle. */
|
||||
(void)proc_rdagent(phdl);
|
||||
|
||||
map = proc_obj2map(phdl, target_prog_file);
|
||||
map = proc_name2map(phdl, target_prog_file);
|
||||
ATF_REQUIRE_MSG(map != NULL, "failed to look up map for '%s'",
|
||||
target_prog_file);
|
||||
|
||||
@ -376,8 +373,8 @@ ATF_TC_BODY(signal_forward, tc)
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
|
||||
ATF_TP_ADD_TC(tp, map_alias_obj2map);
|
||||
ATF_TP_ADD_TC(tp, map_alias_name2map);
|
||||
ATF_TP_ADD_TC(tp, map_prefix_name2map);
|
||||
ATF_TP_ADD_TC(tp, map_alias_name2sym);
|
||||
ATF_TP_ADD_TC(tp, symbol_lookup);
|
||||
ATF_TP_ADD_TC(tp, symbol_lookup_fail);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*-
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -31,7 +31,6 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user