Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shared library support for rv-predict. #812

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions doc/trace-spec
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ Right now I have in mind just 28 opcodes, which I assign these numbers:
unblock-sigs 43 // remove signals from the current mask
sig-getset-mask 44 // get old mask, set new mask
sig-get-mask 45 // get old mask
shared-library 46 // shared library data
shared-library-segment 47 // a shared library's segment

The first trace helps the reader to establish an important fact that
lets it interpret the following traces: PC = (0, begin). That
Expand Down Expand Up @@ -606,6 +608,32 @@ trace ::= (delta, 'load[n]') addr value
`self <- tid`
`self.signal_depth <- 0`

| (delta, 'shared-library') libid namelen namechars

The current thread added `delta` to its program counter.
The program used a library with the given name.

`libid` begins on the first 32-bit boundary after the
deltop, and it is 32 bits wide.

`namelen` begins after `libid` and it is 32 bits wide.

`namechars` is an ASCII encoding of the library name. It
begins after `namelen` and it has `namelen` bytes, with
padding added at the end to fill up to a 32 bit boundary.

| (delta, 'shared-library-segment') libid start size

The current thread added `delta` to its program counter.
The library with id `libid` had a segment of `size` bytes,
starting at the `start` pointer.

`libid` begins on the first 32-bit boundary after the
deltop, and it is 32 bits wide.

`start` has the size of a pointer, while `size` is 32 bit
wide.

# History

Major changes from the version that was discussed on all@ mailing list:
Expand Down
2 changes: 1 addition & 1 deletion errors/rv-error/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ opam init
opam update
opam switch 4.03.0
eval `opam config env`
opam install ocp-ocamlres ocamlbuild-atdgen csv uri atdgen
opam install ocp-ocamlres ocamlbuild-atdgen csv uri atdgen atdj
```

## Description
Expand Down
20 changes: 8 additions & 12 deletions llvm/README
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,13 @@ BUILDING

To build both the runtime and the instrumentation pass:

mkdir build
cd build
cmake ..
make
mkcmake PREFIX=$HOME install

After you run make, the two binaries that you need to add RV-Predict
instrumentation to your program are under build/,
After you run mkcmake, the two binaries that you need to add RV-Predict
instrumentation to your program are under $HOME/lib,

pass/rvpinstrument.so
runtime/lib/linux/libclang_rt.tsan-x86_64.a
$HOME/lib/rvpinstrument.so
$HOME/lib/librvprt.a

The LLVM installation on office.runtimeverification.com:2222 is screwed
up, so I recommend fetching and extracting a CLang+LLVM pre-built binary
Expand All @@ -29,19 +26,18 @@ run cmake like so:

cmake -DLLVM_DIR=$HOME/clang+llvm-3.8.1-x86_64-linux-gnu-ubuntu-16.04/share/llvm/cmake ..

USING

To compile your program with RV-Predict instrumentation, follow these
steps, where $BUILD refers to the build directory, build/, above,
steps, where $BUILD refers to the $HOME/lib directory above,
$SRCS refers to your source files, $OBJS to the object files created
from those sources, and $PROG is the program you are building:

Compile each source file, $src in $SRCS:

clang -g -Xclang -load -Xclang $BUILD/pass/rvpinstrument.so -c $src
clang -g -Xclang -load -Xclang $BUILD/rvpinstrument.so -c $src

Link:

clang -o $PROG $OBJS \
-L$BUILD/runtime/lib/linux -lclang_rt.tsan-x86_64 -ldl -lrt -pthread -g
-L$BUILD/lib -lrvprt -ldl -lrt -pthread -g

1 change: 1 addition & 0 deletions llvm/ngrt/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ SRCS+=register.c relay.c ring.c rmw.c rvpsignal.c sigutil.c
SRCS+=supervise.c
SRCS+=thread.c trace.c
SRCS+=intr.c
SRCS+=dynamic_library.c
WARNS=4

.include <mkc.lib.mk>
83 changes: 71 additions & 12 deletions llvm/ngrt/buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,47 @@

#include <assert.h>
#include <stdint.h> /* for uint32_t */
#include <string.h>

#include "nbcompat.h" /* for __arraycount() */
#include "tracefmt.h" /* for rvp_op_t */

typedef struct {
unsigned int b_nwords;
uint32_t b_word[12];
} rvp_buf_t;
uint32_t b_word[];
} rvp_generic_buf_t;

#define RVP_BUF_INITIALIZER (rvp_buf_t){ .b_nwords = 0 }
static rvp_generic_buf_t rvp_generic_buf_t_example;

// The type for a rvp_generic_buf_t with 'capacity' entries in the buffer.
#define RVP_BUF_TYPE(capacity) \
union { \
rvp_generic_buf_t buf; \
char filler[sizeof(rvp_generic_buf_t) + \
(capacity) * sizeof(rvp_generic_buf_t_example.b_word[0])]; \
}

typedef RVP_BUF_TYPE(12) rvp_buf_t;

#define RVP_BUF_GENERIC_INITIALIZER(type) (type){ .buf.b_nwords = 0 }
#define RVP_BUF_INITIALIZER RVP_BUF_GENERIC_INITIALIZER(rvp_buf_t)

#define RVP_BUF_CAPACITY(b) \
((__arraycount((b).filler) - sizeof(rvp_generic_buf_t)) \
/ sizeof((b).buf.b_word[0]))

static inline void
rvp_buf_put(rvp_buf_t *b, uint32_t item)
rvp_buf_generic_put(rvp_generic_buf_t *b, uint32_t item, unsigned int capacity)
{
assert(b->b_nwords < __arraycount(b->b_word));
assert(b->b_nwords < capacity);
b->b_word[b->b_nwords++] = item;
}

#define rvp_buf_put(b, item) \
rvp_buf_generic_put(&((b)->buf), item, RVP_BUF_CAPACITY(*(b)))

static inline void
rvp_buf_put_addr(rvp_buf_t *b, rvp_addr_t addr)
rvp_buf_generic_put_addr(rvp_generic_buf_t *b, rvp_addr_t addr, unsigned int capacity)
{
unsigned int i;
union {
Expand All @@ -31,28 +52,66 @@ rvp_buf_put_addr(rvp_buf_t *b, rvp_addr_t addr)
} addru = {.uaddr = addr};

for (i = 0; i < __arraycount(addru.u32); i++) {
rvp_buf_put(b, addru.u32[i]);
rvp_buf_generic_put(b, addru.u32[i], capacity);
}
}

#define rvp_buf_put_addr(b, item) \
rvp_buf_generic_put_addr(&((b)->buf), item, RVP_BUF_CAPACITY(*(b)))

static inline void
rvp_buf_put_voidptr(rvp_buf_t *b, const void *addr)
rvp_buf_generic_put_voidptr(rvp_generic_buf_t *b, const void *addr, unsigned int capacity)
{
rvp_buf_put_addr(b, (rvp_addr_t)addr);
rvp_buf_generic_put_addr(b, (rvp_addr_t)addr, capacity);
}

#define rvp_buf_put_voidptr(b, item) \
rvp_buf_generic_put_voidptr(&((b)->buf), item, RVP_BUF_CAPACITY(*(b)))

static inline void
rvp_buf_put_u64(rvp_buf_t *b, uint64_t val)
rvp_buf_generic_put_u64(rvp_generic_buf_t *b, uint64_t val, unsigned int capacity)
{
union {
uint64_t u64;
uint32_t u32[2];
} valu = {.u64 = val};

rvp_buf_put(b, valu.u32[0]);
rvp_buf_put(b, valu.u32[1]);
rvp_buf_generic_put(b, valu.u32[0], capacity);
rvp_buf_generic_put(b, valu.u32[1], capacity);
}

#define rvp_buf_put_u64(b, item) \
rvp_buf_generic_put_u64(&((b)->buf), item, RVP_BUF_CAPACITY(*(b)))

static inline void
rvp_buf_generic_put_string(rvp_generic_buf_t *b, const char* str, unsigned int capacity)
{
union {
uint32_t u32;
char c[4];
} value = {.u32 = 0};
int filled = 0;

rvp_buf_generic_put(b, strlen(str), capacity);

for (; *str; str++) {
value.c[filled] = *str;
if (filled == 3) {
filled = 0;
rvp_buf_generic_put(b, value.u32, capacity);
value.u32 = 0;
} else {
filled++;
}
}
if (filled > 0) {
rvp_buf_generic_put(b, value.u32, capacity);
}
}

#define rvp_buf_put_string(b, item) \
rvp_buf_generic_put_string(&((b)->buf), item, RVP_BUF_CAPACITY(*(b)))

void rvp_buf_put_pc_and_op(rvp_buf_t *, const char **, const char *, rvp_op_t);
void rvp_buf_put_cog(rvp_buf_t *, uint64_t);

Expand Down
54 changes: 54 additions & 0 deletions llvm/ngrt/dynamic_library.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include <link.h>

#include "buf.h"
#include "ring.h"
#include "thread.h"
#include "trace.h"

typedef RVP_BUF_TYPE(12 + PATH_MAX) rvp_buf_with_one_path_t;

#define RVP_BUF_WITH_ONE_PATH_INITIALIZER \
RVP_BUF_GENERIC_INITIALIZER(rvp_buf_with_one_path_t)

static uint32_t shared_library_count = 0;

static int
log_shared_library(struct dl_phdr_info *info, size_t size, void *data)
{
rvp_ring_t *r = rvp_ring_for_curthr();
rvp_buf_with_one_path_t b_library = RVP_BUF_WITH_ONE_PATH_INITIALIZER;

int j;
uint32_t this_library_id = shared_library_count;
shared_library_count++;

rvp_buf_put_voidptr(
&b_library, rvp_vec_and_op_to_deltop(0, RVP_OP_SHARED_LIBRARY));

rvp_buf_put(&b_library, this_library_id); // library_id
rvp_buf_put_string(&b_library, info->dlpi_name);
rvp_ring_put_buf(r, b_library);

for (j = 0; j < info->dlpi_phnum; j++) {
// TODO(virgil): filter out segments that are not interesting, e.g. by
// looking at info->dlpi_phdr[j].p_type.
void* addr = (void *)(info->dlpi_addr + info->dlpi_phdr[j].p_vaddr);
Elf32_Word size = info->dlpi_phdr[j].p_memsz;
rvp_buf_t b_segment = RVP_BUF_INITIALIZER;

rvp_ring_t *r = rvp_ring_for_curthr();
rvp_buf_put_pc_and_op(
&b_segment, &r->r_lastpc, r->r_lastpc, RVP_OP_SHARED_LIBRARY_SEGMENT);
rvp_buf_put(&b_segment, this_library_id);
rvp_buf_put_voidptr(&b_segment, addr);
rvp_buf_put(&b_segment, size);
rvp_ring_put_buf(r, b_segment);
}

return 0;
}

void rvpredict_log_shared_libraries()
{
dl_iterate_phdr(log_shared_library, NULL);
}
6 changes: 6 additions & 0 deletions llvm/ngrt/dynamic_library.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef _RVP_DYNAMIC_LIBRARY_H_
#define _RVP_DYNAMIC_LIBRARY_H_

void rvpredict_log_shared_libraries();

#endif // _RVP_DYNAMIC_LIBRARY_H_
4 changes: 2 additions & 2 deletions llvm/ngrt/ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ rvp_ring_init(rvp_ring_t *r, uint32_t *items, size_t nitems)
int
rvp_ring_stdinit(rvp_ring_t *r)
{
const size_t ringsz = pgsz;
const size_t ringsz = ((2 * PATH_MAX) / pgsz + 1) * pgsz;
const size_t items_per_ring = ringsz / sizeof(*r->r_items);
uint32_t *items;

assert(pgsz != 0);
assert(ringsz != 0);

items = calloc(items_per_ring, sizeof(*r->r_items));
if (items == NULL)
Expand Down
5 changes: 3 additions & 2 deletions llvm/ngrt/ring.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,11 @@ rvp_ring_put_multiple(rvp_ring_t *r, const uint32_t *item, int nitems)
}

static inline void
rvp_ring_put_buf(rvp_ring_t *r, rvp_buf_t b)
rvp_ring_generic_put_buf(rvp_ring_t *r, rvp_generic_buf_t *b)
{
rvp_ring_put_multiple(r, &b.b_word[0], b.b_nwords);
rvp_ring_put_multiple(r, &b->b_word[0], b->b_nwords);
}
#define rvp_ring_put_buf(r, b) rvp_ring_generic_put_buf(r, &b.buf)

/* Return `true` if the interruption is unfinished, false otherwise. */
static inline bool
Expand Down
2 changes: 2 additions & 0 deletions llvm/ngrt/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <string.h> /* for strerror(3), strcasecmp(3) */
#include <unistd.h> /* for sysconf */

#include "dynamic_library.h"
#include "init.h"
#include "interpose.h"
#include "relay.h"
Expand Down Expand Up @@ -339,6 +340,7 @@ rvp_postfork_init(void)
* to start.
*/
rvp_thread0_create();
rvpredict_log_shared_libraries();
rvp_relay_create();
rvp_serializer_create();

Expand Down
2 changes: 1 addition & 1 deletion llvm/ngrt/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ typedef struct _threadswitch {

static const rvp_trace_header_t header = {
.th_magic = "RVP_"
, . th_version = {0, 0, 0, 3}
, . th_version = {0, 0, 0, 4}
, .th_byteorder = '0' | ('1' << 8) | ('2' << 16) | ('3' << 24)
, .th_pointer_width = sizeof(rvp_addr_t)
, .th_data_width = sizeof(uint32_t)
Expand Down
17 changes: 17 additions & 0 deletions llvm/ngrt/tracefmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ typedef enum _rvp_op {
, RVP_OP_SIGUNBLOCK = 43 // unblock signals
, RVP_OP_SIGGETSETMASK = 44 // get old mask, set new mask
, RVP_OP_SIGGETMASK = 45 // get current mask
, RVP_OP_SHARED_LIBRARY = 46 // sets data for a shared library.
, RVP_OP_SHARED_LIBRARY_SEGMENT = 47 // data for a segment belonging
// to a shared library.
, RVP_NOPS
} rvp_op_t;

Expand Down Expand Up @@ -217,4 +220,18 @@ typedef struct {
rvp_addr_t addr;
} __packed __aligned(sizeof(uint32_t)) rvp_acquire_release_t;

typedef struct {
rvp_addr_t deltop;
uint32_t id;
uint32_t name_length; // The name does not include the string
uint32_t name[]; // terminator.
} __packed __aligned(sizeof(uint32_t)) rvp_shared_library_t;

typedef struct {
rvp_addr_t deltop;
uint32_t library_id;
rvp_addr_t start_address;
uint32_t size;
} __packed __aligned(sizeof(uint32_t)) rvp_shared_library_segment_t;

#endif /* _RVP_TRACEFMT_H_ */
Loading