Skip to content

[sanitizer_common] Implement address sanitizer on AIX: process memory mapping #138537

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions compiler-rt/lib/sanitizer_common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ set(SANITIZER_SOURCES_NOTERMINATION
sanitizer_platform_limits_solaris.cpp
sanitizer_posix.cpp
sanitizer_printf.cpp
sanitizer_procmaps_aix.cpp
sanitizer_procmaps_common.cpp
sanitizer_procmaps_bsd.cpp
sanitizer_procmaps_fuchsia.cpp
@@ -109,6 +110,7 @@ set(SANITIZER_IMPL_HEADERS
sancov_flags.h
sancov_flags.inc
sanitizer_addrhashmap.h
sanitizer_aix.h
sanitizer_allocator.h
sanitizer_allocator_checks.h
sanitizer_allocator_combined.h
43 changes: 43 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_aix.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===-- sanitizer_aix.h -----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is shared between various sanitizers' runtime libraries and
// provides definitions for AIX-specific functions.
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_AIX_H
#define SANITIZER_AIX_H

#include "sanitizer_platform.h"

#if SANITIZER_AIX
# include "sanitizer_common.h"
# include "sanitizer_posix.h"

struct prmap;
typedef struct prmap prmap_t;

namespace __sanitizer {

struct ProcSelfMapsBuff {
char *data;
uptr mmaped_size;
uptr len;
prmap_t *mapEnd;
};

struct MemoryMappingLayoutData {
ProcSelfMapsBuff proc_self_maps;
const char *current;
};

void ReadProcMaps(ProcSelfMapsBuff *proc_maps);

} // namespace __sanitizer

#endif // SANITIZER_AIX
#endif // SANITIZER_AIX_H
17 changes: 9 additions & 8 deletions compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
Original file line number Diff line number Diff line change
@@ -17,14 +17,15 @@

#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
SANITIZER_APPLE || SANITIZER_SOLARIS || SANITIZER_HAIKU || \
SANITIZER_FUCHSIA

#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_fuchsia.h"
#include "sanitizer_linux.h"
#include "sanitizer_mac.h"
#include "sanitizer_mutex.h"
SANITIZER_FUCHSIA || SANITIZER_AIX

# include "sanitizer_aix.h"
# include "sanitizer_common.h"
# include "sanitizer_fuchsia.h"
# include "sanitizer_internal_defs.h"
# include "sanitizer_linux.h"
# include "sanitizer_mac.h"
# include "sanitizer_mutex.h"

namespace __sanitizer {

132 changes: 132 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//===-- sanitizer_procmaps_aix.cpp ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Information about the process mappings (AIX-specific parts).
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"

#if SANITIZER_AIX
# include <assert.h>
# include <stdio.h>
# include <stdlib.h>
# include <sys/procfs.h>

# include "sanitizer_common.h"
# include "sanitizer_file.h"
# include "sanitizer_procmaps.h"

namespace __sanitizer {

static int qsort_comp(const void *va, const void *vb) {
const prmap_t *a = (const prmap_t *)va;
const prmap_t *b = (const prmap_t *)vb;

if (a->pr_vaddr < b->pr_vaddr)
return -1;

if (a->pr_vaddr > b->pr_vaddr)
return 1;

return 0;
}

static prmap_t *SortProcMapEntries(char *buffer) {
prmap_t *begin = (prmap_t *)buffer;
prmap_t *mapIter = begin;
// The AIX procmap utility detects the end of the array of `prmap`s by finding
// an entry where pr_size and pr_vaddr are both zero.
while (mapIter->pr_size != 0 || mapIter->pr_vaddr != 0) ++mapIter;
prmap_t *end = mapIter;

size_t count = end - begin;
size_t elemSize = sizeof(prmap_t);
qsort(begin, count, elemSize, qsort_comp);

return end;
}

void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
uptr pid = internal_getpid();
constexpr unsigned BUFFER_SIZE = 128;
char filenameBuf[BUFFER_SIZE] = {};
internal_snprintf(filenameBuf, BUFFER_SIZE, "/proc/%d/map", pid);
if (!ReadFileToBuffer(filenameBuf, &proc_maps->data, &proc_maps->mmaped_size,
&proc_maps->len)) {
proc_maps->data = nullptr;
proc_maps->mmaped_size = 0;
proc_maps->len = 0;
proc_maps->mapEnd = nullptr;
return;
}

proc_maps->mapEnd = SortProcMapEntries(proc_maps->data);
}

bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
if (Error())
return false; // simulate empty maps

const prmap_t *mapIter = (const prmap_t *)data_.current;

if (mapIter >= data_.proc_self_maps.mapEnd)
return false;

// Skip the kernel segment.
if ((mapIter->pr_mflags & MA_TYPE_MASK) == MA_KERNTEXT)
++mapIter;

if (mapIter >= data_.proc_self_maps.mapEnd)
return false;

segment->start = (uptr)mapIter->pr_vaddr;
segment->end = segment->start + mapIter->pr_size;

segment->protection = 0;
uint32_t flags = mapIter->pr_mflags;
if (flags & MA_READ)
segment->protection |= kProtectionRead;
if (flags & MA_WRITE)
segment->protection |= kProtectionWrite;
if (flags & MA_EXEC)
segment->protection |= kProtectionExecute;

uint32_t type = mapIter->pr_mflags & MA_TYPE_MASK;
if (type == MA_SLIBTEXT || type == MA_PLIBDATA)
segment->protection |= kProtectionShared;

if (segment->filename && mapIter->pr_pathoff) {
uptr len;
constexpr unsigned BUFFER_SIZE = 128;
char objPath[BUFFER_SIZE] = {};
// Use path /proc/<pid>/object/<object_id>
// TODO: Pass a separate path from mapIter->pr_pathoff to display to the
// user.
// TODO: Append the archive member name if it exists.
internal_snprintf(objPath, BUFFER_SIZE, "/proc/%d/object/%s",
internal_getpid(), mapIter->pr_mapname);
len = Min((uptr)internal_strlen(objPath), segment->filename_size - 1);
internal_strncpy(segment->filename, objPath, len);
segment->filename[len] = 0;

} else if (segment->filename) {
segment->filename[0] = 0;
}

assert(mapIter->pr_off == 0 && "expect a zero offset into module.");
segment->offset = 0;

++mapIter;
data_.current = (const char *)mapIter;

return true;
}

} // namespace __sanitizer

#endif // SANITIZER_AIX
10 changes: 5 additions & 5 deletions compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp
Original file line number Diff line number Diff line change
@@ -11,12 +11,12 @@

#include "sanitizer_platform.h"

#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_SOLARIS || SANITIZER_AIX

#include "sanitizer_common.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
# include "sanitizer_common.h"
# include "sanitizer_placement_new.h"
# include "sanitizer_procmaps.h"

namespace __sanitizer {

Loading