Skip to content

Commit

Permalink
i#2266: Dump memory layout to json file on annotation (#2267)
Browse files Browse the repository at this point in the history
Adds a new annotation DRMEMORY_ANNOTATE_DUMP_MEMORY_LAYOUT() which
triggers dumping the memory layout to a new file "memlayout.nnnn.log"
in the log subdirectory, where "nnnn" is incremented on each
successive dump.  The file is in JSON format.

Exports annotation support by building the required .c file with
custom flags as a library, and exports it and the two required header
files drmemory_annotations.h and dr_annotations_asm.h.

A basic block whose tag matches the address of the symbol "main" in
the executable is watched for.  Heap allocations prior to that point
are marked with a new flag MALLOC_BEFORE_MAIN.  The stack pointer at
that point is recorded.

At dump time, a heap iteration is done, skipping MALLOC_BEFORE_MAIN
objects.  Each object is placed into a tree.  Each thread stack is
also placed into a trace; fof the primary thread, only the stack
region between the recorded main stack point and the TOS is
considered.  Both trees are then walked, with each memory region
walked in pointer-sized chunks, printing out values and whether values
look like pointers to the top or middle of other objects in either
tree.

This feature and its annotation are disabled if asm-goto is not supported
by the compiler (clang<9.0), determined by try-compile.

Adds a test "memlayout".  Parameterizes runtest.cmake to allow
checking memlayout*.json instead of results.txt.  CMake is having
trouble with square brackets (it always did, but there are many of
them in json files), so runtest.cmake now replaces them with angle as
a workaround.

If jsonlint-php is found, runs it on each generated json file in the
test to ensure there are no syntax errors.  We install jsonlint on Travis.

Documentation will be added later once post-processing is ironed out.

Issue: #2266
  • Loading branch information
derekbruening authored Mar 1, 2020
1 parent 4c77bb7 commit af3a792
Show file tree
Hide file tree
Showing 20 changed files with 713 additions and 78 deletions.
12 changes: 11 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ jobs:
- if: type != cron AND env(TRAVIS_EVENT_TYPE) != cron
os: linux
compiler: clang
# We need clang 9.0 for asm goto support (DRi#1799) for annotations.
env: CC=clang-9 CXX=clang++-9
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
packages:
- clang-9
- if: type != cron AND env(TRAVIS_EVENT_TYPE) != cron
os: osx
compiler: clang
Expand All @@ -78,7 +88,7 @@ install:
# XXX: Remove the "brew update" step once Travis fixes their Mac VM's
# on 11/15/17. Xref https://github.com/travis-ci/travis-ci/issues/8552.
- if [[ "`uname`" == "Darwin" ]]; then brew update; brew install nasm; fi
- if [[ "`uname`" == "Linux" ]]; then sudo apt-get -y install g++-multilib doxygen; fi
- if [[ "`uname`" == "Linux" ]]; then sudo apt-get -y install g++-multilib doxygen jsonlint; fi

script:
- tests/runsuite_wrapper.pl travis
Expand Down
117 changes: 85 additions & 32 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,7 @@ else (TOOL_DR_HEAPSTAT)
drmemory/report.c
drmemory/replace.c
drmemory/leak.c
drmemory/memlayout.c
drmemory/perturb.c
common/utils.c
common/utils_shared.c
Expand Down Expand Up @@ -1688,6 +1689,70 @@ else (WIN32)
endif (WIN32)
copy_file_to_device("${defsupp_out}")

###########################################################################
# Dr. Memory Framework (DRMF) setup needed for tests

set(DRMF_BASEDIR "drmf")
set(DRMF_BINBASE "${LIB_ARCH}/${build_type}")
set(DRMF_INSTALL "${INSTALL_PREFIX}${DRMF_BASEDIR}")
set(DRMF_INSTALL_BIN "${DRMF_INSTALL}/${DRMF_BINBASE}")
set(DRMF_INSTALL_INC "${DRMF_INSTALL}/include")
set(framework_dir "${PROJECT_BINARY_DIR}/${DRMF_BASEDIR}")
set(framework_incdir "${framework_dir}/include")
set(framework_bindir "${framework_dir}/${DRMF_BINBASE}")

# Versioning: we use separate versioning for DRMF from the tool versioning.
# This is major*100 + minor.
set(DRMF_VERSION_DEFAULT "1.0.${VERSION_NUMBER_PATCHLEVEL}")
set(DRMF_VERSION "" CACHE STRING "DRMF version number: leave empty for default")
if ("${DRMF_VERSION}" STREQUAL "")
set(DRMF_VERSION ${DRMF_VERSION_DEFAULT})
endif()
message(STATUS "DRMF version number: ${DRMF_VERSION}")
string(REGEX REPLACE "^([0-9]+)\\..*" "\\1" DRMF_VERSION_MAJOR "${DRMF_VERSION}")
string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\..*" "\\1" DRMF_VERSION_MINOR "${DRMF_VERSION}")
# We use just major.minor for .so versioning (and no, SOVERSION is not sufficient
# here: we have to set VERSION to control the file name and import dependence).
string(REGEX REPLACE "^([0-9]+\\.[0-9]+)\\..*" "\\1"
DRMF_VERSION_MAJOR_MINOR "${DRMF_VERSION}")
math(EXPR DRMF_VERSION_INTEGER "${DRMF_VERSION_MAJOR}*100 + ${DRMF_VERSION_MINOR}")
set(DRMF_VERSION_COMPAT 9) # Oldest compatible version
set(DRMF_VERSION_CUR ${DRMF_VERSION_INTEGER}) # Current version

configure_file(framework/public.h
${framework_incdir}/drmemory_framework.h)
configure_file(drmemory/annotations_public.h
${framework_incdir}/drmemory_annotations.h)
configure_file(${DynamoRIO_DIR}/../include/annotations/dr_annotations_asm.h
${framework_incdir}/dr_annotations_asm.h)
configure_file(${DynamoRIO_DIR}/../include/annotations/dr_annotations.h
${framework_incdir}/dr_annotations.h)
include_directories(${framework_incdir})

# Annotation support using DR's infrastructure (non-Valgrind-style).
if (UNIX)
set(annot_cflags "-O0 -Wno-unused-variable -Wno-return-type")
else ()
set(annot_cflags "/Od /Ob0 /GL- /wd4715")
endif ()
if (UNIX)
# DRi#1799: clang prior to 9.0 does not support "asm goto" which is used by
# the DR annotation infrastructure. But, we can't just do a version check
# because Apple's clang has a completely separate version number.
try_compile(DR_ANNOTATIONS_SUPPORTED ${PROJECT_BINARY_DIR}/try_annot
SOURCES ${PROJECT_SOURCE_DIR}/tests/memlayout.cpp
${PROJECT_SOURCE_DIR}/drmemory/annotations_public.c CMAKE_FLAGS
-DINCLUDE_DIRECTORIES=${framework_incdir}
-DCMAKE_C_FLAGS:STRING="${annot_cflags}")
if (DR_ANNOTATIONS_SUPPORTED)
message(STATUS "DR annotations are supported")
else ()
message(STATUS "DR annotations are NOT supported: probably this is clang<9.0")
endif ()
else ()
set(DR_ANNOTATIONS_SUPPORTED ON)
endif ()

###########################################################################
# Tests

Expand Down Expand Up @@ -1766,37 +1831,6 @@ endif ()
# framework-shared code goes here. Things that should be global we
# put into functions for invocation inside extension subdirs.

set(DRMF_BASEDIR "drmf")
set(DRMF_BINBASE "${LIB_ARCH}/${build_type}")
set(DRMF_INSTALL "${INSTALL_PREFIX}${DRMF_BASEDIR}")
set(DRMF_INSTALL_BIN "${DRMF_INSTALL}/${DRMF_BINBASE}")
set(DRMF_INSTALL_INC "${DRMF_INSTALL}/include")
set(framework_dir "${PROJECT_BINARY_DIR}/${DRMF_BASEDIR}")
set(framework_incdir "${framework_dir}/include")
set(framework_bindir "${framework_dir}/${DRMF_BINBASE}")

# Versioning: we use separate versioning for DRMF from the tool versioning.
# This is major*100 + minor.
set(DRMF_VERSION_DEFAULT "1.0.${VERSION_NUMBER_PATCHLEVEL}")
set(DRMF_VERSION "" CACHE STRING "DRMF version number: leave empty for default")
if ("${DRMF_VERSION}" STREQUAL "")
set(DRMF_VERSION ${DRMF_VERSION_DEFAULT})
endif()
message(STATUS "DRMF version number: ${DRMF_VERSION}")
string(REGEX REPLACE "^([0-9]+)\\..*" "\\1" DRMF_VERSION_MAJOR "${DRMF_VERSION}")
string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\..*" "\\1" DRMF_VERSION_MINOR "${DRMF_VERSION}")
# We use just major.minor for .so versioning (and no, SOVERSION is not sufficient
# here: we have to set VERSION to control the file name and import dependence).
string(REGEX REPLACE "^([0-9]+\\.[0-9]+)\\..*" "\\1"
DRMF_VERSION_MAJOR_MINOR "${DRMF_VERSION}")
math(EXPR DRMF_VERSION_INTEGER "${DRMF_VERSION_MAJOR}*100 + ${DRMF_VERSION_MINOR}")
set(DRMF_VERSION_COMPAT 9) # Oldest compatible version
set(DRMF_VERSION_CUR ${DRMF_VERSION_INTEGER}) # Current version

configure_file(framework/public.h
${framework_incdir}/drmemory_framework.h)
include_directories(${framework_incdir})

configure_file(framework/drmf.cmake.in
${framework_dir}/DrMemoryFrameworkConfig.cmake
@ONLY)
Expand Down Expand Up @@ -1842,6 +1876,20 @@ SET_PROPERTY(TARGET ${ARGV0} PROPERTY MAP_IMPORTED_CONFIG_RELMINSIZE RelWithDebI
set(exported_targets_append "${exported_targets_append}" PARENT_SCOPE)
endmacro(export_target)

if (DR_ANNOTATIONS_SUPPORTED)
add_library(drmemory_annotations STATIC drmemory/annotations_public.c)
# TODO i#2266: Provide a CMake function like use_DynamoRIO_annotations.
# We would both use it here and export it.
# For now we make a library, which is actually a little easier than the
# user having to compile our source file with special flags.
# So the CMake function would just set up the include path and link to the lib.
_DR_append_property_string(SOURCE drmemory/annotations_public.c
COMPILE_FLAGS "${annot_cflags}")
export_target(drmemory_annotations)
install(TARGETS drmemory_annotations EXPORT ${exported_targets_name}
DESTINATION ${DRMF_INSTALL_BIN})
endif ()

# Included prior to add_subdirectory() for building version.c which
# includes utils.h which includes drsyscall.h.
include_directories(drsyscall)
Expand Down Expand Up @@ -2188,7 +2236,12 @@ else (BUILDING_SUB_PACKAGE)
endif (BUILDING_SUB_PACKAGE)

# DRMF install rules
install(FILES ${framework_incdir}/drmemory_framework.h DESTINATION ${DRMF_INSTALL_INC})
install(FILES
${framework_incdir}/drmemory_framework.h
${framework_incdir}/drmemory_annotations.h
${framework_incdir}/dr_annotations.h
${framework_incdir}/dr_annotations_asm.h
DESTINATION ${DRMF_INSTALL_INC})
install(FILES ${framework_dir}/DrMemoryFrameworkConfigVersion.cmake
${framework_dir}/DrMemoryFrameworkConfig.cmake
DESTINATION ${DRMF_INSTALL})
Expand Down
7 changes: 5 additions & 2 deletions common/alloc.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2010-2017 Google, Inc. All rights reserved.
* Copyright (c) 2010-2020 Google, Inc. All rights reserved.
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -118,8 +118,11 @@ enum {
MALLOC_RESERVED_7 = 0x0400,
MALLOC_RESERVED_8 = 0x0800,
MALLOC_RESERVED_9 = 0x1000,
MALLOC_RESERVED_10= 0x2000,
MALLOC_CLIENT_5 = 0x4000,
MALLOC_POSSIBLE_CLIENT_FLAGS = (MALLOC_CLIENT_1 | MALLOC_CLIENT_2 |
MALLOC_CLIENT_3 | MALLOC_CLIENT_4),
MALLOC_CLIENT_3 | MALLOC_CLIENT_4 |
MALLOC_CLIENT_5),
};

/* Info on a malloc chunk used for malloc iteration and client notification */
Expand Down
4 changes: 2 additions & 2 deletions common/alloc_replace.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ enum {
/* i#1532: only check for non-static libc. This is Windows-only but it's
* cleaner to avoid all the ifdefs down below.
*/
CHUNK_LAYER_NOCHECK = 0x1000,
CHUNK_SKIP_ITER = 0x2000,
CHUNK_LAYER_NOCHECK = MALLOC_RESERVED_9,
CHUNK_SKIP_ITER = MALLOC_RESERVED_10,

/* meta-flags */
#ifdef WINDOWS
Expand Down
6 changes: 5 additions & 1 deletion drmemory/alloc_drmem.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2010-2019 Google, Inc. All rights reserved.
* Copyright (c) 2010-2020 Google, Inc. All rights reserved.
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -31,6 +31,7 @@
#include "heap.h"
#include "redblack.h"
#include "leak.h"
#include "memlayout.h"
#include "alloc_drmem.h"
#ifdef UNIX
# ifdef MACOS
Expand Down Expand Up @@ -232,6 +233,8 @@ alloc_drmem_init(void)
end_of_defined_region,
is_register_defined);

memlayout_init();

if (options.delay_frees > 0) {
delay_free_lock = dr_mutex_create();
delay_free_tree = rb_tree_create(NULL);
Expand Down Expand Up @@ -549,6 +552,7 @@ client_handle_malloc(void *drcontext, malloc_info_t *mal, dr_mcontext_t *mc)
report_malloc(mal->base, mal->base + mal->request_size,
mal->realloc ? "realloc" : "malloc", mc);
leak_handle_alloc(drcontext, mal->base, mal->request_size);
memlayout_handle_alloc(drcontext, mal->base, mal->request_size);
}

void
Expand Down
2 changes: 1 addition & 1 deletion drmemory/alloc_drmem.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2013-2017 Google, Inc. All rights reserved.
* Copyright (c) 2013-2020 Google, Inc. All rights reserved.
* Copyright (c) 2008-2009 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down
20 changes: 19 additions & 1 deletion drmemory/annotations.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2015 Google, Inc. All rights reserved.
* Copyright (c) 2011-2020 Google, Inc. All rights reserved.
* **********************************************************/

/* Dr. Memory: the memory debugger
Expand Down Expand Up @@ -40,6 +40,7 @@
#include "options.h"
#ifdef TOOL_DR_MEMORY
# include "alloc_drmem.h"
# include "memlayout.h"
#else
extern void check_reachability(bool at_exit);
#endif
Expand Down Expand Up @@ -74,6 +75,13 @@ handle_do_leak_check(dr_vg_client_request_t *request)
check_reachability(false/*!at_exit*/);
return 0;
}

void handle_dump_memory_layout(void)
{
# ifdef TOOL_DR_MEMORY
memlayout_dump_layout();
# endif
}
#endif

void
Expand All @@ -88,6 +96,16 @@ annotate_init(void)
handle_do_leak_check);
# endif
#endif

#ifndef ARM /* FIXME DRi#1672: add ARM annotation support to DR */
/* TODO i#2266: We want to pass the PC to the handler. */
if (!dr_annotation_register_call("drmemory_dump_memory_layout",
handle_dump_memory_layout, false, 0,
DR_ANNOTATION_CALL_TYPE_FASTCALL)) {
NOTIFY_ERROR("ERROR: Failed to register annotations"NL);
dr_abort();
}
#endif
}

void
Expand Down
24 changes: 24 additions & 0 deletions drmemory/annotations_public.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* **********************************************************
* Copyright (c) 2020 Google, Inc. All rights reserved.
* **********************************************************/

/* Dr. Memory: the memory debugger
*
* 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;
* version 2.1 of the License, and no 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
* Library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "dr_annotations.h"

DR_DEFINE_ANNOTATION(void, drmemory_dump_memory_layout, (void),)
45 changes: 45 additions & 0 deletions drmemory/annotations_public.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* **********************************************************
* Copyright (c) 2020 Google, Inc. All rights reserved.
* **********************************************************/

/* Dr. Memory: the memory debugger
*
* 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;
* version 2.1 of the License, and no 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
* Library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef _ANNOTATIONS_PUBLIC_H_
#define _ANNOTATIONS_PUBLIC_H_ 1

#include "dr_annotations_asm.h"

/* To simplify project configuration, this pragma excludes the file from GCC warnings. */
#ifdef __GNUC__
# pragma GCC system_header
#endif

#define DRMEMORY_ANNOTATE_DUMP_MEMORY_LAYOUT() \
DR_ANNOTATION(drmemory_dump_memory_layout)

#ifdef __cplusplus
extern "C" {
#endif

DR_DECLARE_ANNOTATION(void, drmemory_dump_memory_layout, (void));

#ifdef __cplusplus
}
#endif

#endif /* _ANNOTATIONS_PUBLIC_H_ */
5 changes: 4 additions & 1 deletion drmemory/instru.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2010-2017 Google, Inc. All rights reserved.
* Copyright (c) 2010-2020 Google, Inc. All rights reserved.
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -29,6 +29,7 @@
#include "drutil.h"
#include "drmemory.h"
#include "slowpath.h"
#include "memlayout.h"
#include "spill.h"
#include "fastpath.h"
#include "stack.h"
Expand Down Expand Up @@ -1002,6 +1003,8 @@ instru_event_bb_analysis(void *drcontext, void *tag, instrlist_t *bb,
LOG(4, "ilist before analysis:\n");
DOLOG(4, instrlist_disassemble(drcontext, tag, bb, LOGFILE_GET(drcontext)););

memlayout_handle_new_block(drcontext, tag);

#ifdef USE_DRSYMS
/* symbol of each bb is very useful for debugging */
DOLOG(3, {
Expand Down
1 change: 1 addition & 0 deletions drmemory/leak.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ enum {
MALLOC_MAYBE_REACHABLE = MALLOC_CLIENT_3,
/* Indirect leak (PR 576032) */
MALLOC_INDIRECTLY_REACHABLE = MALLOC_CLIENT_4,
MALLOC_BEFORE_MAIN = MALLOC_CLIENT_5,
};

/* the lowest possbile pointer value */
Expand Down
Loading

0 comments on commit af3a792

Please sign in to comment.