mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* configure fix for environment variables (Daniel) * fix memory leaks (Alex) * x86_64 MTTCG fixes (Emilio) * introduce atomic64 (Emilio) * Fix for virtio hang (Fam, myself) * SH serial port fix (Geert) * Deprecate rotation_rate for scsi-block (Fam) * Extend memory-backend-file availability to all POSIX hosts (Hikaru) * Memory API cleanups and fixes (Igor, Li Qiang, Peter, Philippe) * MSI/IOMMU fix (Jan) * Socket reconnection fixes (Marc-André) * icount fixes (Emilio, myself) * QSP fixes for Coverity (myself) * Some record/replay improovements (Pavel) * Packed struct fixes (Peter) * Windows dump fixes and elf2dmp (Viktor) * kbmclock fix (Yongji) # gpg: Signature made Tue 02 Oct 2018 18:13:12 BST # gpg: using RSA key BFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: (80 commits) hw/scsi/mptendian: Avoid taking address of fields in packed structs cpus: fix TCG kick timer leak docs/devel/memory.txt: Document _with_attrs accessors hw/nvram/fw_cfg: Use memberwise copy of MemoryRegionOps struct memory: Remove old_mmio accessors memory: Fix access_with_adjusted_size(small size) on big-endian memory regions memory: Refactor common shifting code from accessors memory: Use MAKE_64BIT_MASK() virtio: do not take address of packed members replay: replay BH for IDE trim operation hostmem-file: make available memory-backend-file on POSIX-based hosts target/i386: fix translation for icount mode hvf: drop unused variable qom/object: add some interface asserts accel/tcg: Remove dead code lsi53c895a: convert to trace-events scsi-block: Deprecate rotation_rate kvmclock: run KVM_KVMCLOCK_CTRL ioctl in vcpu thread MAINTAINERS: add myself as elf2dmp maintainer contrib: add elf2dmp tool ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -1903,6 +1903,11 @@ S: Maintained
|
||||
F: include/qemu/iova-tree.h
|
||||
F: util/iova-tree.c
|
||||
|
||||
elf2dmp
|
||||
M: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
|
||||
S: Maintained
|
||||
F: contrib/elf2dmp/
|
||||
|
||||
Usermode Emulation
|
||||
------------------
|
||||
Overall
|
||||
|
||||
@@ -415,6 +415,7 @@ dummy := $(call unnest-vars,, \
|
||||
chardev-obj-y \
|
||||
util-obj-y \
|
||||
qga-obj-y \
|
||||
elf2dmp-obj-y \
|
||||
ivshmem-client-obj-y \
|
||||
ivshmem-server-obj-y \
|
||||
libvhost-user-obj-y \
|
||||
@@ -710,6 +711,10 @@ ifneq ($(EXESUF),)
|
||||
qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI)
|
||||
endif
|
||||
|
||||
elf2dmp: LIBS = $(CURL_LIBS)
|
||||
elf2dmp: $(elf2dmp-obj-y)
|
||||
$(call LINK, $^)
|
||||
|
||||
ifdef CONFIG_IVSHMEM
|
||||
ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
|
||||
@@ -186,6 +186,7 @@ qga-vss-dll-obj-y = qga/
|
||||
|
||||
######################################################################
|
||||
# contrib
|
||||
elf2dmp-obj-y = contrib/elf2dmp/
|
||||
ivshmem-client-obj-$(CONFIG_IVSHMEM) = contrib/ivshmem-client/
|
||||
ivshmem-server-obj-$(CONFIG_IVSHMEM) = contrib/ivshmem-server/
|
||||
libvhost-user-obj-y = contrib/libvhost-user/
|
||||
|
||||
@@ -2009,15 +2009,6 @@ void tb_invalidate_phys_page_fast(struct page_collection *pages,
|
||||
{
|
||||
PageDesc *p;
|
||||
|
||||
#if 0
|
||||
if (1) {
|
||||
qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
|
||||
cpu_single_env->mem_io_vaddr, len,
|
||||
cpu_single_env->eip,
|
||||
cpu_single_env->eip +
|
||||
(intptr_t)cpu_single_env->segs[R_CS].base);
|
||||
}
|
||||
#endif
|
||||
assert_memory_lock();
|
||||
|
||||
p = page_find(start >> TARGET_PAGE_BITS);
|
||||
|
||||
@@ -34,6 +34,8 @@ void translator_loop_temp_check(DisasContextBase *db)
|
||||
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
CPUState *cpu, TranslationBlock *tb)
|
||||
{
|
||||
int bp_insn = 0;
|
||||
|
||||
/* Initialize DisasContext */
|
||||
db->tb = tb;
|
||||
db->pc_first = tb->pc;
|
||||
@@ -71,11 +73,13 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
||||
/* Pass breakpoint hits to target for further processing */
|
||||
if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
|
||||
if (!db->singlestep_enabled
|
||||
&& unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
|
||||
CPUBreakpoint *bp;
|
||||
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
|
||||
if (bp->pc == db->pc_next) {
|
||||
if (ops->breakpoint_check(db, cpu, bp)) {
|
||||
bp_insn = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -118,7 +122,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
|
||||
/* Emit code to exit the TB, as indicated by db->is_jmp. */
|
||||
ops->tb_stop(db, cpu);
|
||||
gen_tb_end(db->tb, db->num_insns);
|
||||
gen_tb_end(db->tb, db->num_insns - bp_insn);
|
||||
|
||||
/* The disas_log hook may use these values rather than recompute. */
|
||||
db->tb->size = db->pc_next - db->pc_first;
|
||||
|
||||
@@ -4,7 +4,7 @@ common-obj-$(CONFIG_POSIX) += rng-random.o
|
||||
common-obj-$(CONFIG_TPM) += tpm.o
|
||||
|
||||
common-obj-y += hostmem.o hostmem-ram.o
|
||||
common-obj-$(CONFIG_LINUX) += hostmem-file.o
|
||||
common-obj-$(CONFIG_POSIX) += hostmem-file.o
|
||||
|
||||
common-obj-y += cryptodev.o
|
||||
common-obj-y += cryptodev-builtin.o
|
||||
|
||||
@@ -51,7 +51,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
error_setg(errp, "mem-path property not set");
|
||||
return;
|
||||
}
|
||||
#ifndef CONFIG_LINUX
|
||||
#ifndef CONFIG_POSIX
|
||||
error_setg(errp, "-mem-path not supported on this host");
|
||||
#else
|
||||
if (!host_memory_backend_mr_inited(backend)) {
|
||||
|
||||
+19
-13
@@ -140,18 +140,22 @@ memfd_backend_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
bc->alloc = memfd_backend_memory_alloc;
|
||||
|
||||
object_class_property_add_bool(oc, "hugetlb",
|
||||
memfd_backend_get_hugetlb,
|
||||
memfd_backend_set_hugetlb,
|
||||
&error_abort);
|
||||
object_class_property_add(oc, "hugetlbsize", "int",
|
||||
memfd_backend_get_hugetlbsize,
|
||||
memfd_backend_set_hugetlbsize,
|
||||
NULL, NULL, &error_abort);
|
||||
object_class_property_add_bool(oc, "seal",
|
||||
memfd_backend_get_seal,
|
||||
memfd_backend_set_seal,
|
||||
&error_abort);
|
||||
if (qemu_memfd_check(MFD_HUGETLB)) {
|
||||
object_class_property_add_bool(oc, "hugetlb",
|
||||
memfd_backend_get_hugetlb,
|
||||
memfd_backend_set_hugetlb,
|
||||
&error_abort);
|
||||
object_class_property_add(oc, "hugetlbsize", "int",
|
||||
memfd_backend_get_hugetlbsize,
|
||||
memfd_backend_set_hugetlbsize,
|
||||
NULL, NULL, &error_abort);
|
||||
}
|
||||
if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
|
||||
object_class_property_add_bool(oc, "seal",
|
||||
memfd_backend_get_seal,
|
||||
memfd_backend_set_seal,
|
||||
&error_abort);
|
||||
}
|
||||
}
|
||||
|
||||
static const TypeInfo memfd_backend_info = {
|
||||
@@ -164,7 +168,9 @@ static const TypeInfo memfd_backend_info = {
|
||||
|
||||
static void register_types(void)
|
||||
{
|
||||
type_register_static(&memfd_backend_info);
|
||||
if (qemu_memfd_check(0)) {
|
||||
type_register_static(&memfd_backend_info);
|
||||
}
|
||||
}
|
||||
|
||||
type_init(register_types);
|
||||
|
||||
@@ -31,10 +31,6 @@
|
||||
|
||||
#include "chardev/char-io.h"
|
||||
|
||||
#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
|
||||
|| defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
|
||||
|| defined(__GLIBC__)
|
||||
|
||||
typedef struct {
|
||||
Chardev parent;
|
||||
QIOChannel *ioc;
|
||||
@@ -299,5 +295,3 @@ static void register_types(void)
|
||||
}
|
||||
|
||||
type_init(register_types);
|
||||
|
||||
#endif
|
||||
|
||||
+36
-50
@@ -32,7 +32,6 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/clone-visitor.h"
|
||||
#include "qapi/qapi-visit-sockets.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
#include "chardev/char-io.h"
|
||||
|
||||
@@ -354,6 +353,15 @@ static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
|
||||
return qio_channel_create_watch(s->ioc, cond);
|
||||
}
|
||||
|
||||
static void remove_hup_source(SocketChardev *s)
|
||||
{
|
||||
if (s->hup_source != NULL) {
|
||||
g_source_destroy(s->hup_source);
|
||||
g_source_unref(s->hup_source);
|
||||
s->hup_source = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void tcp_chr_free_connection(Chardev *chr)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||
@@ -368,11 +376,7 @@ static void tcp_chr_free_connection(Chardev *chr)
|
||||
s->read_msgfds_num = 0;
|
||||
}
|
||||
|
||||
if (s->hup_source != NULL) {
|
||||
g_source_destroy(s->hup_source);
|
||||
g_source_unref(s->hup_source);
|
||||
s->hup_source = NULL;
|
||||
}
|
||||
remove_hup_source(s);
|
||||
|
||||
tcp_set_msgfds(chr, NULL, 0);
|
||||
remove_fd_in_watch(chr);
|
||||
@@ -541,6 +545,27 @@ static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len,
|
||||
}
|
||||
}
|
||||
|
||||
static void update_ioc_handlers(SocketChardev *s)
|
||||
{
|
||||
Chardev *chr = CHARDEV(s);
|
||||
|
||||
if (!s->connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
remove_fd_in_watch(chr);
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
tcp_chr_read_poll,
|
||||
tcp_chr_read, chr,
|
||||
chr->gcontext);
|
||||
|
||||
remove_hup_source(s);
|
||||
s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP);
|
||||
g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup,
|
||||
chr, NULL);
|
||||
g_source_attach(s->hup_source, chr->gcontext);
|
||||
}
|
||||
|
||||
static void tcp_chr_connect(void *opaque)
|
||||
{
|
||||
Chardev *chr = CHARDEV(opaque);
|
||||
@@ -553,16 +578,7 @@ static void tcp_chr_connect(void *opaque)
|
||||
s->is_listen, s->is_telnet);
|
||||
|
||||
s->connected = 1;
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
tcp_chr_read_poll,
|
||||
tcp_chr_read,
|
||||
chr, chr->gcontext);
|
||||
|
||||
s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP);
|
||||
g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup,
|
||||
chr, NULL);
|
||||
g_source_attach(s->hup_source, chr->gcontext);
|
||||
|
||||
update_ioc_handlers(s);
|
||||
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
|
||||
}
|
||||
|
||||
@@ -593,17 +609,7 @@ static void tcp_chr_update_read_handler(Chardev *chr)
|
||||
tcp_chr_telnet_init(CHARDEV(s));
|
||||
}
|
||||
|
||||
if (!s->connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
remove_fd_in_watch(chr);
|
||||
if (s->ioc) {
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
tcp_chr_read_poll,
|
||||
tcp_chr_read, chr,
|
||||
chr->gcontext);
|
||||
}
|
||||
update_ioc_handlers(s);
|
||||
}
|
||||
|
||||
static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
|
||||
@@ -724,11 +730,6 @@ static void tcp_chr_tls_init(Chardev *chr)
|
||||
Error *err = NULL;
|
||||
gchar *name;
|
||||
|
||||
if (!machine_init_done) {
|
||||
/* This will be postponed to machine_done notifier */
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->is_listen) {
|
||||
tioc = qio_channel_tls_new_server(
|
||||
s->ioc, s->tls_creds,
|
||||
@@ -1011,8 +1012,9 @@ static void qmp_chardev_open_socket(Chardev *chr,
|
||||
s->reconnect_time = reconnect;
|
||||
}
|
||||
|
||||
/* If reconnect_time is set, will do that in chr_machine_done. */
|
||||
if (!s->reconnect_time) {
|
||||
if (s->reconnect_time) {
|
||||
tcp_chr_connect_async(chr);
|
||||
} else {
|
||||
if (s->is_listen) {
|
||||
char *name;
|
||||
s->listener = qio_net_listener_new();
|
||||
@@ -1161,21 +1163,6 @@ char_socket_get_connected(Object *obj, Error **errp)
|
||||
return s->connected;
|
||||
}
|
||||
|
||||
static int tcp_chr_machine_done_hook(Chardev *chr)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||
|
||||
if (s->reconnect_time) {
|
||||
tcp_chr_connect_async(chr);
|
||||
}
|
||||
|
||||
if (s->ioc && s->tls_creds) {
|
||||
tcp_chr_tls_init(chr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void char_socket_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||
@@ -1191,7 +1178,6 @@ static void char_socket_class_init(ObjectClass *oc, void *data)
|
||||
cc->chr_add_client = tcp_chr_add_client;
|
||||
cc->chr_add_watch = tcp_chr_add_watch;
|
||||
cc->chr_update_read_handler = tcp_chr_update_read_handler;
|
||||
cc->chr_machine_done = tcp_chr_machine_done_hook;
|
||||
|
||||
object_class_property_add(oc, "addr", "SocketAddress",
|
||||
char_socket_get_addr, NULL,
|
||||
|
||||
@@ -5721,6 +5721,9 @@ if test "$want_tools" = "yes" ; then
|
||||
if [ "$ivshmem" = "yes" ]; then
|
||||
tools="ivshmem-client\$(EXESUF) ivshmem-server\$(EXESUF) $tools"
|
||||
fi
|
||||
if [ "$posix" = "yes" ] && [ "$curl" = "yes" ]; then
|
||||
tools="elf2dmp $tools"
|
||||
fi
|
||||
fi
|
||||
if test "$softmmu" = yes ; then
|
||||
if test "$linux" = yes; then
|
||||
@@ -7024,12 +7027,14 @@ TARGET_ABI_DIR=""
|
||||
|
||||
case "$target_name" in
|
||||
i386)
|
||||
mttcg="yes"
|
||||
gdb_xml_files="i386-32bit.xml i386-32bit-core.xml i386-32bit-sse.xml"
|
||||
target_compiler=$cross_cc_i386
|
||||
target_compiler_cflags=$cross_cc_ccflags_i386
|
||||
;;
|
||||
x86_64)
|
||||
TARGET_BASE_ARCH=i386
|
||||
mttcg="yes"
|
||||
gdb_xml_files="i386-64bit.xml i386-64bit-core.xml i386-64bit-sse.xml"
|
||||
target_compiler=$cross_cc_x86_64
|
||||
;;
|
||||
@@ -7527,6 +7532,46 @@ cat <<EOD >config.status
|
||||
# Compiler output produced by configure, useful for debugging
|
||||
# configure, is in config.log if it exists.
|
||||
EOD
|
||||
|
||||
preserve_env() {
|
||||
envname=$1
|
||||
|
||||
eval envval=\$$envname
|
||||
|
||||
if test -n "$envval"
|
||||
then
|
||||
echo "$envname='$envval'" >> config.status
|
||||
echo "export $envname" >> config.status
|
||||
else
|
||||
echo "unset $envname" >> config.status
|
||||
fi
|
||||
}
|
||||
|
||||
# Preserve various env variables that influence what
|
||||
# features/build target configure will detect
|
||||
preserve_env AR
|
||||
preserve_env AS
|
||||
preserve_env CC
|
||||
preserve_env CPP
|
||||
preserve_env CXX
|
||||
preserve_env INSTALL
|
||||
preserve_env LD
|
||||
preserve_env LD_LIBRARY_PATH
|
||||
preserve_env LIBTOOL
|
||||
preserve_env MAKE
|
||||
preserve_env NM
|
||||
preserve_env OBJCOPY
|
||||
preserve_env PATH
|
||||
preserve_env PKG_CONFIG
|
||||
preserve_env PKG_CONFIG_LIBDIR
|
||||
preserve_env PKG_CONFIG_PATH
|
||||
preserve_env PYTHON
|
||||
preserve_env SDL_CONFIG
|
||||
preserve_env SDL2_CONFIG
|
||||
preserve_env SMBD
|
||||
preserve_env STRIP
|
||||
preserve_env WINDRES
|
||||
|
||||
printf "exec" >>config.status
|
||||
printf " '%s'" "$0" "$@" >>config.status
|
||||
echo ' "$@"' >>config.status
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
elf2dmp-obj-y = main.o addrspace.o download.o pdb.o qemu_elf.o
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Virtuozzo International GmbH
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "addrspace.h"
|
||||
|
||||
static struct pa_block *pa_space_find_block(struct pa_space *ps, uint64_t pa)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < ps->block_nr; i++) {
|
||||
if (ps->block[i].paddr <= pa &&
|
||||
pa <= ps->block[i].paddr + ps->block[i].size) {
|
||||
return ps->block + i;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint8_t *pa_space_resolve(struct pa_space *ps, uint64_t pa)
|
||||
{
|
||||
struct pa_block *block = pa_space_find_block(ps, pa);
|
||||
|
||||
if (!block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return block->addr + (pa - block->paddr);
|
||||
}
|
||||
|
||||
int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
|
||||
{
|
||||
Elf64_Half phdr_nr = elf_getphdrnum(qemu_elf->map);
|
||||
Elf64_Phdr *phdr = elf64_getphdr(qemu_elf->map);
|
||||
size_t block_i = 0;
|
||||
size_t i;
|
||||
|
||||
ps->block_nr = 0;
|
||||
|
||||
for (i = 0; i < phdr_nr; i++) {
|
||||
if (phdr[i].p_type == PT_LOAD) {
|
||||
ps->block_nr++;
|
||||
}
|
||||
}
|
||||
|
||||
ps->block = malloc(sizeof(*ps->block) * ps->block_nr);
|
||||
if (!ps->block) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < phdr_nr; i++) {
|
||||
if (phdr[i].p_type == PT_LOAD) {
|
||||
ps->block[block_i] = (struct pa_block) {
|
||||
.addr = (uint8_t *)qemu_elf->map + phdr[i].p_offset,
|
||||
.paddr = phdr[i].p_paddr,
|
||||
.size = phdr[i].p_filesz,
|
||||
};
|
||||
block_i++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pa_space_destroy(struct pa_space *ps)
|
||||
{
|
||||
ps->block_nr = 0;
|
||||
free(ps->block);
|
||||
}
|
||||
|
||||
void va_space_set_dtb(struct va_space *vs, uint64_t dtb)
|
||||
{
|
||||
vs->dtb = dtb & 0x00ffffffffff000;
|
||||
}
|
||||
|
||||
void va_space_create(struct va_space *vs, struct pa_space *ps, uint64_t dtb)
|
||||
{
|
||||
vs->ps = ps;
|
||||
va_space_set_dtb(vs, dtb);
|
||||
}
|
||||
|
||||
static uint64_t get_pml4e(struct va_space *vs, uint64_t va)
|
||||
{
|
||||
uint64_t pa = (vs->dtb & 0xffffffffff000) | ((va & 0xff8000000000) >> 36);
|
||||
|
||||
return *(uint64_t *)pa_space_resolve(vs->ps, pa);
|
||||
}
|
||||
|
||||
static uint64_t get_pdpi(struct va_space *vs, uint64_t va, uint64_t pml4e)
|
||||
{
|
||||
uint64_t pdpte_paddr = (pml4e & 0xffffffffff000) |
|
||||
((va & 0x7FC0000000) >> 27);
|
||||
|
||||
return *(uint64_t *)pa_space_resolve(vs->ps, pdpte_paddr);
|
||||
}
|
||||
|
||||
static uint64_t pde_index(uint64_t va)
|
||||
{
|
||||
return (va >> 21) & 0x1FF;
|
||||
}
|
||||
|
||||
static uint64_t pdba_base(uint64_t pdpe)
|
||||
{
|
||||
return pdpe & 0xFFFFFFFFFF000;
|
||||
}
|
||||
|
||||
static uint64_t get_pgd(struct va_space *vs, uint64_t va, uint64_t pdpe)
|
||||
{
|
||||
uint64_t pgd_entry = pdba_base(pdpe) + pde_index(va) * 8;
|
||||
|
||||
return *(uint64_t *)pa_space_resolve(vs->ps, pgd_entry);
|
||||
}
|
||||
|
||||
static uint64_t pte_index(uint64_t va)
|
||||
{
|
||||
return (va >> 12) & 0x1FF;
|
||||
}
|
||||
|
||||
static uint64_t ptba_base(uint64_t pde)
|
||||
{
|
||||
return pde & 0xFFFFFFFFFF000;
|
||||
}
|
||||
|
||||
static uint64_t get_pte(struct va_space *vs, uint64_t va, uint64_t pgd)
|
||||
{
|
||||
uint64_t pgd_val = ptba_base(pgd) + pte_index(va) * 8;
|
||||
|
||||
return *(uint64_t *)pa_space_resolve(vs->ps, pgd_val);
|
||||
}
|
||||
|
||||
static uint64_t get_paddr(uint64_t va, uint64_t pte)
|
||||
{
|
||||
return (pte & 0xFFFFFFFFFF000) | (va & 0xFFF);
|
||||
}
|
||||
|
||||
static bool is_present(uint64_t entry)
|
||||
{
|
||||
return entry & 0x1;
|
||||
}
|
||||
|
||||
static bool page_size_flag(uint64_t entry)
|
||||
{
|
||||
return entry & (1 << 7);
|
||||
}
|
||||
|
||||
static uint64_t get_1GB_paddr(uint64_t va, uint64_t pdpte)
|
||||
{
|
||||
return (pdpte & 0xfffffc0000000) | (va & 0x3fffffff);
|
||||
}
|
||||
|
||||
static uint64_t get_2MB_paddr(uint64_t va, uint64_t pgd_entry)
|
||||
{
|
||||
return (pgd_entry & 0xfffffffe00000) | (va & 0x00000001fffff);
|
||||
}
|
||||
|
||||
static uint64_t va_space_va2pa(struct va_space *vs, uint64_t va)
|
||||
{
|
||||
uint64_t pml4e, pdpe, pgd, pte;
|
||||
|
||||
pml4e = get_pml4e(vs, va);
|
||||
if (!is_present(pml4e)) {
|
||||
return INVALID_PA;
|
||||
}
|
||||
|
||||
pdpe = get_pdpi(vs, va, pml4e);
|
||||
if (!is_present(pdpe)) {
|
||||
return INVALID_PA;
|
||||
}
|
||||
|
||||
if (page_size_flag(pdpe)) {
|
||||
return get_1GB_paddr(va, pdpe);
|
||||
}
|
||||
|
||||
pgd = get_pgd(vs, va, pdpe);
|
||||
if (!is_present(pgd)) {
|
||||
return INVALID_PA;
|
||||
}
|
||||
|
||||
if (page_size_flag(pgd)) {
|
||||
return get_2MB_paddr(va, pgd);
|
||||
}
|
||||
|
||||
pte = get_pte(vs, va, pgd);
|
||||
if (!is_present(pte)) {
|
||||
return INVALID_PA;
|
||||
}
|
||||
|
||||
return get_paddr(va, pte);
|
||||
}
|
||||
|
||||
void *va_space_resolve(struct va_space *vs, uint64_t va)
|
||||
{
|
||||
uint64_t pa = va_space_va2pa(vs, va);
|
||||
|
||||
if (pa == INVALID_PA) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pa_space_resolve(vs->ps, pa);
|
||||
}
|
||||
|
||||
int va_space_rw(struct va_space *vs, uint64_t addr,
|
||||
void *buf, size_t size, int is_write)
|
||||
{
|
||||
while (size) {
|
||||
uint64_t page = addr & PFN_MASK;
|
||||
size_t s = (page + PAGE_SIZE) - addr;
|
||||
void *ptr;
|
||||
|
||||
s = (s > size) ? size : s;
|
||||
|
||||
ptr = va_space_resolve(vs, addr);
|
||||
if (!ptr) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (is_write) {
|
||||
memcpy(ptr, buf, s);
|
||||
} else {
|
||||
memcpy(buf, ptr, s);
|
||||
}
|
||||
|
||||
size -= s;
|
||||
buf = (uint8_t *)buf + s;
|
||||
addr += s;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Virtuozzo International GmbH
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ADDRSPACE_H
|
||||
#define ADDRSPACE_H
|
||||
|
||||
#include "qemu_elf.h"
|
||||
|
||||
#define PAGE_BITS 12
|
||||
#define PAGE_SIZE (1ULL << PAGE_BITS)
|
||||
#define PFN_MASK (~(PAGE_SIZE - 1))
|
||||
|
||||
#define INVALID_PA UINT64_MAX
|
||||
|
||||
struct pa_block {
|
||||
uint8_t *addr;
|
||||
uint64_t paddr;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
struct pa_space {
|
||||
size_t block_nr;
|
||||
struct pa_block *block;
|
||||
};
|
||||
|
||||
struct va_space {
|
||||
uint64_t dtb;
|
||||
struct pa_space *ps;
|
||||
};
|
||||
|
||||
int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf);
|
||||
void pa_space_destroy(struct pa_space *ps);
|
||||
|
||||
void va_space_create(struct va_space *vs, struct pa_space *ps, uint64_t dtb);
|
||||
void va_space_set_dtb(struct va_space *vs, uint64_t dtb);
|
||||
void *va_space_resolve(struct va_space *vs, uint64_t va);
|
||||
int va_space_rw(struct va_space *vs, uint64_t addr,
|
||||
void *buf, size_t size, int is_write);
|
||||
|
||||
#endif /* ADDRSPACE_H */
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Virtuozzo International GmbH
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <curl/curl.h>
|
||||
#include "download.h"
|
||||
|
||||
int download_url(const char *name, const char *url)
|
||||
{
|
||||
int err = 0;
|
||||
FILE *file;
|
||||
CURL *curl = curl_easy_init();
|
||||
|
||||
if (!curl) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
file = fopen(name, "wb");
|
||||
if (!file) {
|
||||
err = 1;
|
||||
goto out_curl;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
||||
|
||||
if (curl_easy_perform(curl) != CURLE_OK) {
|
||||
err = 1;
|
||||
fclose(file);
|
||||
unlink(name);
|
||||
goto out_curl;
|
||||
}
|
||||
|
||||
err = fclose(file);
|
||||
|
||||
out_curl:
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Virtuozzo International GmbH
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DOWNLOAD_H
|
||||
#define DOWNLOAD_H
|
||||
|
||||
int download_url(const char *name, const char *url);
|
||||
|
||||
#endif /* DOWNLOAD_H */
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Virtuozzo International GmbH
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ERR_H
|
||||
#define ERR_H
|
||||
|
||||
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
|
||||
|
||||
#endif /* ERR_H */
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Virtuozzo International GmbH
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KDBG_H
|
||||
#define KDBG_H
|
||||
|
||||
typedef struct DBGKD_GET_VERSION64 {
|
||||
uint16_t MajorVersion;
|
||||
uint16_t MinorVersion;
|
||||
uint8_t ProtocolVersion;
|
||||
uint8_t KdSecondaryVersion;
|
||||
uint16_t Flags;
|
||||
uint16_t MachineType;
|
||||
uint8_t MaxPacketType;
|
||||
uint8_t MaxStateChange;
|
||||
uint8_t MaxManipulate;
|
||||
uint8_t Simulation;
|
||||
uint16_t Unused[1];
|
||||
uint64_t KernBase;
|
||||
uint64_t PsLoadedModuleList;
|
||||
uint64_t DebuggerDataList;
|
||||
} DBGKD_GET_VERSION64;
|
||||
|
||||
typedef struct DBGKD_DEBUG_DATA_HEADER64 {
|
||||
struct LIST_ENTRY64 {
|
||||
struct LIST_ENTRY64 *Flink;
|
||||
struct LIST_ENTRY64 *Blink;
|
||||
} List;
|
||||
uint32_t OwnerTag;
|
||||
uint32_t Size;
|
||||
} DBGKD_DEBUG_DATA_HEADER64;
|
||||
|
||||
typedef struct KDDEBUGGER_DATA64 {
|
||||
DBGKD_DEBUG_DATA_HEADER64 Header;
|
||||
|
||||
uint64_t KernBase;
|
||||
uint64_t BreakpointWithStatus;
|
||||
uint64_t SavedContext;
|
||||
uint16_t ThCallbackStack;
|
||||
uint16_t NextCallback;
|
||||
uint16_t FramePointer;
|
||||
uint16_t PaeEnabled:1;
|
||||
uint64_t KiCallUserMode;
|
||||
uint64_t KeUserCallbackDispatcher;
|
||||
uint64_t PsLoadedModuleList;
|
||||
uint64_t PsActiveProcessHead;
|
||||
uint64_t PspCidTable;
|
||||
uint64_t ExpSystemResourcesList;
|
||||
uint64_t ExpPagedPoolDescriptor;
|
||||
uint64_t ExpNumberOfPagedPools;
|
||||
uint64_t KeTimeIncrement;
|
||||
uint64_t KeBugCheckCallbackListHead;
|
||||
uint64_t KiBugcheckData;
|
||||
uint64_t IopErrorLogListHead;
|
||||
uint64_t ObpRootDirectoryObject;
|
||||
uint64_t ObpTypeObjectType;
|
||||
uint64_t MmSystemCacheStart;
|
||||
uint64_t MmSystemCacheEnd;
|
||||
uint64_t MmSystemCacheWs;
|
||||
uint64_t MmPfnDatabase;
|
||||
uint64_t MmSystemPtesStart;
|
||||
uint64_t MmSystemPtesEnd;
|
||||
uint64_t MmSubsectionBase;
|
||||
uint64_t MmNumberOfPagingFiles;
|
||||
uint64_t MmLowestPhysicalPage;
|
||||
uint64_t MmHighestPhysicalPage;
|
||||
uint64_t MmNumberOfPhysicalPages;
|
||||
uint64_t MmMaximumNonPagedPoolInBytes;
|
||||
uint64_t MmNonPagedSystemStart;
|
||||
uint64_t MmNonPagedPoolStart;
|
||||
uint64_t MmNonPagedPoolEnd;
|
||||
uint64_t MmPagedPoolStart;
|
||||
uint64_t MmPagedPoolEnd;
|
||||
uint64_t MmPagedPoolInformation;
|
||||
uint64_t MmPageSize;
|
||||
uint64_t MmSizeOfPagedPoolInBytes;
|
||||
uint64_t MmTotalCommitLimit;
|
||||
uint64_t MmTotalCommittedPages;
|
||||
uint64_t MmSharedCommit;
|
||||
uint64_t MmDriverCommit;
|
||||
uint64_t MmProcessCommit;
|
||||
uint64_t MmPagedPoolCommit;
|
||||
uint64_t MmExtendedCommit;
|
||||
uint64_t MmZeroedPageListHead;
|
||||
uint64_t MmFreePageListHead;
|
||||
uint64_t MmStandbyPageListHead;
|
||||
uint64_t MmModifiedPageListHead;
|
||||
uint64_t MmModifiedNoWritePageListHead;
|
||||
uint64_t MmAvailablePages;
|
||||
uint64_t MmResidentAvailablePages;
|
||||
uint64_t PoolTrackTable;
|
||||
uint64_t NonPagedPoolDescriptor;
|
||||
uint64_t MmHighestUserAddress;
|
||||
uint64_t MmSystemRangeStart;
|
||||
uint64_t MmUserProbeAddress;
|
||||
uint64_t KdPrintCircularBuffer;
|
||||
uint64_t KdPrintCircularBufferEnd;
|
||||
uint64_t KdPrintWritePointer;
|
||||
uint64_t KdPrintRolloverCount;
|
||||
uint64_t MmLoadedUserImageList;
|
||||
|
||||
/* NT 5.1 Addition */
|
||||
|
||||
uint64_t NtBuildLab;
|
||||
uint64_t KiNormalSystemCall;
|
||||
|
||||
/* NT 5.0 hotfix addition */
|
||||
|
||||
uint64_t KiProcessorBlock;
|
||||
uint64_t MmUnloadedDrivers;
|
||||
uint64_t MmLastUnloadedDriver;
|
||||
uint64_t MmTriageActionTaken;
|
||||
uint64_t MmSpecialPoolTag;
|
||||
uint64_t KernelVerifier;
|
||||
uint64_t MmVerifierData;
|
||||
uint64_t MmAllocatedNonPagedPool;
|
||||
uint64_t MmPeakCommitment;
|
||||
uint64_t MmTotalCommitLimitMaximum;
|
||||
uint64_t CmNtCSDVersion;
|
||||
|
||||
/* NT 5.1 Addition */
|
||||
|
||||
uint64_t MmPhysicalMemoryBlock;
|
||||
uint64_t MmSessionBase;
|
||||
uint64_t MmSessionSize;
|
||||
uint64_t MmSystemParentTablePage;
|
||||
|
||||
/* Server 2003 addition */
|
||||
|
||||
uint64_t MmVirtualTranslationBase;
|
||||
uint16_t OffsetKThreadNextProcessor;
|
||||
uint16_t OffsetKThreadTeb;
|
||||
uint16_t OffsetKThreadKernelStack;
|
||||
uint16_t OffsetKThreadInitialStack;
|
||||
uint16_t OffsetKThreadApcProcess;
|
||||
uint16_t OffsetKThreadState;
|
||||
uint16_t OffsetKThreadBStore;
|
||||
uint16_t OffsetKThreadBStoreLimit;
|
||||
uint16_t SizeEProcess;
|
||||
uint16_t OffsetEprocessPeb;
|
||||
uint16_t OffsetEprocessParentCID;
|
||||
uint16_t OffsetEprocessDirectoryTableBase;
|
||||
uint16_t SizePrcb;
|
||||
uint16_t OffsetPrcbDpcRoutine;
|
||||
uint16_t OffsetPrcbCurrentThread;
|
||||
uint16_t OffsetPrcbMhz;
|
||||
uint16_t OffsetPrcbCpuType;
|
||||
uint16_t OffsetPrcbVendorString;
|
||||
uint16_t OffsetPrcbProcStateContext;
|
||||
uint16_t OffsetPrcbNumber;
|
||||
uint16_t SizeEThread;
|
||||
uint64_t KdPrintCircularBufferPtr;
|
||||
uint64_t KdPrintBufferSize;
|
||||
uint64_t KeLoaderBlock;
|
||||
uint16_t SizePcr;
|
||||
uint16_t OffsetPcrSelfPcr;
|
||||
uint16_t OffsetPcrCurrentPrcb;
|
||||
uint16_t OffsetPcrContainedPrcb;
|
||||
uint16_t OffsetPcrInitialBStore;
|
||||
uint16_t OffsetPcrBStoreLimit;
|
||||
uint16_t OffsetPcrInitialStack;
|
||||
uint16_t OffsetPcrStackLimit;
|
||||
uint16_t OffsetPrcbPcrPage;
|
||||
uint16_t OffsetPrcbProcStateSpecialReg;
|
||||
uint16_t GdtR0Code;
|
||||
uint16_t GdtR0Data;
|
||||
uint16_t GdtR0Pcr;
|
||||
uint16_t GdtR3Code;
|
||||
uint16_t GdtR3Data;
|
||||
uint16_t GdtR3Teb;
|
||||
uint16_t GdtLdt;
|
||||
uint16_t GdtTss;
|
||||
uint16_t Gdt64R3CmCode;
|
||||
uint16_t Gdt64R3CmTeb;
|
||||
uint64_t IopNumTriageDumpDataBlocks;
|
||||
uint64_t IopTriageDumpDataBlocks;
|
||||
|
||||
/* Longhorn addition */
|
||||
|
||||
uint64_t VfCrashDataBlock;
|
||||
uint64_t MmBadPagesDetected;
|
||||
uint64_t MmZeroedPageSingleBitErrorsDetected;
|
||||
|
||||
/* Windows 7 addition */
|
||||
|
||||
uint64_t EtwpDebuggerData;
|
||||
uint16_t OffsetPrcbContext;
|
||||
} KDDEBUGGER_DATA64;
|
||||
|
||||
#endif /* KDBG_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Virtuozzo International GmbH
|
||||
*
|
||||
* Based on source of Wine project
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "pdb.h"
|
||||
#include "err.h"
|
||||
|
||||
static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx)
|
||||
{
|
||||
return r->ds.toc->file_size[idx];
|
||||
}
|
||||
|
||||
static pdb_seg *get_seg_by_num(struct pdb_reader *r, size_t n)
|
||||
{
|
||||
size_t i = 0;
|
||||
char *ptr;
|
||||
|
||||
for (ptr = r->segs; (ptr < r->segs + r->segs_size); ) {
|
||||
i++;
|
||||
ptr += 8;
|
||||
if (i == n) {
|
||||
break;
|
||||
}
|
||||
ptr += sizeof(pdb_seg);
|
||||
}
|
||||
|
||||
return (pdb_seg *)ptr;
|
||||
}
|
||||
|
||||
uint64_t pdb_find_public_v3_symbol(struct pdb_reader *r, const char *name)
|
||||
{
|
||||
size_t size = pdb_get_file_size(r, r->symbols->gsym_file);
|
||||
int length;
|
||||
const union codeview_symbol *sym;
|
||||
const uint8_t *root = r->modimage;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < size; i += length) {
|
||||
sym = (const void *)(root + i);
|
||||
length = sym->generic.len + 2;
|
||||
|
||||
if (!sym->generic.id || length < 4) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (sym->generic.id == S_PUB_V3 &&
|
||||
!strcmp(name, sym->public_v3.name)) {
|
||||
pdb_seg *segment = get_seg_by_num(r, sym->public_v3.segment);
|
||||
uint32_t sect_rva = segment->dword[1];
|
||||
uint64_t rva = sect_rva + sym->public_v3.offset;
|
||||
|
||||
printf("%s: 0x%016x(%d:\'%.8s\') + 0x%08x = 0x%09lx\n", name,
|
||||
sect_rva, sym->public_v3.segment,
|
||||
((char *)segment - 8), sym->public_v3.offset, rva);
|
||||
return rva;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t pdb_resolve(uint64_t img_base, struct pdb_reader *r, const char *name)
|
||||
{
|
||||
uint64_t rva = pdb_find_public_v3_symbol(r, name);
|
||||
|
||||
if (!rva) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return img_base + rva;
|
||||
}
|
||||
|
||||
static void pdb_reader_ds_exit(struct pdb_reader *r)
|
||||
{
|
||||
free(r->ds.toc);
|
||||
}
|
||||
|
||||
static void pdb_exit_symbols(struct pdb_reader *r)
|
||||
{
|
||||
free(r->modimage);
|
||||
free(r->symbols);
|
||||
}
|
||||
|
||||
static void pdb_exit_segments(struct pdb_reader *r)
|
||||
{
|
||||
free(r->segs);
|
||||
}
|
||||
|
||||
static void *pdb_ds_read(const PDB_DS_HEADER *header,
|
||||
const uint32_t *block_list, int size)
|
||||
{
|
||||
int i, nBlocks;
|
||||
uint8_t *buffer;
|
||||
|
||||
if (!size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nBlocks = (size + header->block_size - 1) / header->block_size;
|
||||
|
||||
buffer = malloc(nBlocks * header->block_size);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < nBlocks; i++) {
|
||||
memcpy(buffer + i * header->block_size, (const char *)header +
|
||||
block_list[i] * header->block_size, header->block_size);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void *pdb_ds_read_file(struct pdb_reader* r, uint32_t file_number)
|
||||
{
|
||||
const uint32_t *block_list;
|
||||
uint32_t block_size;
|
||||
const uint32_t *file_size;
|
||||
size_t i;
|
||||
|
||||
if (!r->ds.toc || file_number >= r->ds.toc->num_files) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file_size = r->ds.toc->file_size;
|
||||
r->file_used[file_number / 32] |= 1 << (file_number % 32);
|
||||
|
||||
if (file_size[file_number] == 0 || file_size[file_number] == 0xFFFFFFFF) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block_list = file_size + r->ds.toc->num_files;
|
||||
block_size = r->ds.header->block_size;
|
||||
|
||||
for (i = 0; i < file_number; i++) {
|
||||
block_list += (file_size[i] + block_size - 1) / block_size;
|
||||
}
|
||||
|
||||
return pdb_ds_read(r->ds.header, block_list, file_size[file_number]);
|
||||
}
|
||||
|
||||
static int pdb_init_segments(struct pdb_reader *r)
|
||||
{
|
||||
char *segs;
|
||||
unsigned stream_idx = r->sidx.segments;
|
||||
|
||||
segs = pdb_ds_read_file(r, stream_idx);
|
||||
if (!segs) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
r->segs = segs;
|
||||
r->segs_size = pdb_get_file_size(r, stream_idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pdb_init_symbols(struct pdb_reader *r)
|
||||
{
|
||||
int err = 0;
|
||||
PDB_SYMBOLS *symbols;
|
||||
PDB_STREAM_INDEXES *sidx = &r->sidx;
|
||||
|
||||
memset(sidx, -1, sizeof(*sidx));
|
||||
|
||||
symbols = pdb_ds_read_file(r, 3);
|
||||
if (!symbols) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
r->symbols = symbols;
|
||||
|
||||
if (symbols->stream_index_size != sizeof(PDB_STREAM_INDEXES)) {
|
||||
err = 1;
|
||||
goto out_symbols;
|
||||
}
|
||||
|
||||
memcpy(sidx, (const char *)symbols + sizeof(PDB_SYMBOLS) +
|
||||
symbols->module_size + symbols->offset_size +
|
||||
symbols->hash_size + symbols->srcmodule_size +
|
||||
symbols->pdbimport_size + symbols->unknown2_size, sizeof(*sidx));
|
||||
|
||||
/* Read global symbol table */
|
||||
r->modimage = pdb_ds_read_file(r, symbols->gsym_file);
|
||||
if (!r->modimage) {
|
||||
err = 1;
|
||||
goto out_symbols;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_symbols:
|
||||
free(symbols);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
|
||||
{
|
||||
memset(r->file_used, 0, sizeof(r->file_used));
|
||||
r->ds.header = hdr;
|
||||
r->ds.toc = pdb_ds_read(hdr, (uint32_t *)((uint8_t *)hdr +
|
||||
hdr->toc_page * hdr->block_size), hdr->toc_size);
|
||||
|
||||
if (!r->ds.toc) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pdb_reader_init(struct pdb_reader *r, void *data)
|
||||
{
|
||||
int err = 0;
|
||||
const char pdb7[] = "Microsoft C/C++ MSF 7.00";
|
||||
|
||||
if (memcmp(data, pdb7, sizeof(pdb7) - 1)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pdb_reader_ds_init(r, data)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
r->ds.root = pdb_ds_read_file(r, 1);
|
||||
if (!r->ds.root) {
|
||||
err = 1;
|
||||
goto out_ds;
|
||||
}
|
||||
|
||||
if (pdb_init_symbols(r)) {
|
||||
err = 1;
|
||||
goto out_root;
|
||||
}
|
||||
|
||||
if (pdb_init_segments(r)) {
|
||||
err = 1;
|
||||
goto out_sym;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_sym:
|
||||
pdb_exit_symbols(r);
|
||||
out_root:
|
||||
free(r->ds.root);
|
||||
out_ds:
|
||||
pdb_reader_ds_exit(r);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void pdb_reader_exit(struct pdb_reader *r)
|
||||
{
|
||||
pdb_exit_segments(r);
|
||||
pdb_exit_symbols(r);
|
||||
free(r->ds.root);
|
||||
pdb_reader_ds_exit(r);
|
||||
}
|
||||
|
||||
int pdb_init_from_file(const char *name, struct pdb_reader *reader)
|
||||
{
|
||||
int err = 0;
|
||||
int fd;
|
||||
void *map;
|
||||
struct stat st;
|
||||
|
||||
fd = open(name, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
eprintf("Failed to open PDB file \'%s\'\n", name);
|
||||
return 1;
|
||||
}
|
||||
reader->fd = fd;
|
||||
|
||||
fstat(fd, &st);
|
||||
reader->file_size = st.st_size;
|
||||
|
||||
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (map == MAP_FAILED) {
|
||||
eprintf("Failed to map PDB file\n");
|
||||
err = 1;
|
||||
goto out_fd;
|
||||
}
|
||||
|
||||
if (pdb_reader_init(reader, map)) {
|
||||
err = 1;
|
||||
goto out_unmap;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_unmap:
|
||||
munmap(map, st.st_size);
|
||||
out_fd:
|
||||
close(fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void pdb_exit(struct pdb_reader *reader)
|
||||
{
|
||||
munmap(reader->ds.header, reader->file_size);
|
||||
close(reader->fd);
|
||||
pdb_reader_exit(reader);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user