<commit_before>#include <pthread.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/types.h>
#include <android/log.h>

#include "bin/src/halide_hexagon_remote.h"

namespace {

typedef halide_hexagon_remote_handle_t handle_t;
typedef halide_hexagon_remote_buffer buffer;

typedef int ion_user_handle_t;

struct ion_allocation_data {
	size_t len;
	size_t align;
	unsigned int heap_id_mask;
	unsigned int flags;
	ion_user_handle_t handle;
};

struct ion_fd_data {
	ion_user_handle_t handle;
	int fd;
};

struct ion_handle_data {
	ion_user_handle_t handle;
};

#define ION_IOC_ALLOC _IOWR('I', 0, ion_allocation_data)
#define ION_IOC_FREE _IOWR('I', 1, ion_handle_data)
#define ION_IOC_MAP _IOWR('I', 2, ion_fd_data)

ion_user_handle_t ion_alloc(int ion_fd, size_t len, size_t align, unsigned int heap_id_mask, unsigned int flags) {
    ion_allocation_data alloc = {
        len,
        align,
        heap_id_mask,
        flags,
        0
    };
    if (ioctl(ion_fd, ION_IOC_ALLOC, &alloc) < 0) {
        return -1;
    }
    return alloc.handle;
}

int ion_map(int ion_fd, ion_user_handle_t handle) {
    ion_fd_data data = {
        handle,
        0
    };
    if (ioctl(ion_fd, ION_IOC_MAP, &data) < 0) {
        return -1;
    }
    return data.fd;
}

int ion_free(int ion_fd, ion_user_handle_t ion_handle) {
    if(ioctl(ion_fd, ION_IOC_FREE, &ion_handle) < 0) {
        return -1;
    }
    return 0;
}

struct allocation_record {
    allocation_record *next;
    int ion_fd;
    ion_user_handle_t handle;
    int buf_fd;
    void *buf;
    size_t size;
};

// Make a dummy allocation so we don't need a special case for the head node.
allocation_record allocations = { NULL, };
pthread_mutex_t allocations_mutex;

}  // namespace

extern "C" {

__attribute__((weak)) void remote_register_buf(void* buf, int size, int fd);

void halide_hexagon_host_malloc_init() {
    pthread_mutex_init(&allocations_mutex, NULL);
}

void halide_hexagon_host_malloc_deinit() {
    pthread_mutex_destroy(&allocations_mutex);
}

void *halide_hexagon_host_malloc(size_t size) {
    int ion_fd = open("/dev/ion", O_RDONLY, 0);
    if (ion_fd < 0) {
        __android_log_print(ANDROID_LOG_ERROR, "halide", "open('/dev/ion') failed");
        return NULL;
    }

    const int heap_id = 25;  // system heap
    const int ion_flags = 1;  // cached

    // Hexagon can only access a small number of mappings of these
    // sizes. We reduce the number of mappings required by aligning
    // large allocations to these sizes.
    static const size_t alignments[] = { 0x1000, 0x4000, 0x10000, 0x40000, 0x100000 };
    size_t alignment = alignments[0];

    // Align the size up to the minimum alignment.
    size = (size + alignment - 1) & ~(alignment - 1);

    if (heap_id != 25) {
        for (size_t i = 0; i < sizeof(alignments) / sizeof(alignments[0]); i++) {
            if (size >= alignments[i]) {
                alignment = alignments[i];
            }
        }
    }

    ion_user_handle_t handle = ion_alloc(ion_fd, size, alignment, 1 << heap_id, ion_flags);
    if (handle < 0) {
        __android_log_print(ANDROID_LOG_ERROR, "halide", "ion_alloc(ion_fd, %d, %d, %d, %d) failed",
                            size, alignment, 1 << heap_id, ion_flags);
        close(ion_fd);
        return NULL;
    }

    // Map the ion handle to a file buffer.
    int buf_fd = ion_map(ion_fd, handle);
    if (buf_fd < 0) {
        __android_log_print(ANDROID_LOG_ERROR, "halide", "ion_map(ion_fd, %d", handle);
        ion_free(ion_fd, handle);
        close(ion_fd);
        return NULL;
    }

    // Map the file buffer to a pointer.
    void *buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, buf_fd, 0);
    if (buf == MAP_FAILED) {
        __android_log_print(ANDROID_LOG_ERROR, "halide", "mmap(NULL, %d, PROT_READ | PROT_WRITE, MAP_SHARED, %d, 0)",
                            size, buf_fd);
        ion_free(ion_fd, handle);
        close(ion_fd);
        return NULL;
    }

    // Register the buffer, so we get zero copy.
    if (remote_register_buf) {
        remote_register_buf(buf, size, buf_fd);
    }

    // Build a record for this allocation.
    allocation_record *rec = (allocation_record *)malloc(sizeof(allocation_record));
    if (!rec) {
        __android_log_print(ANDROID_LOG_ERROR, "halide", "malloc failed");
        munmap(buf, size);
        ion_free(ion_fd, handle);
        close(ion_fd);
        return NULL;
    }

    rec->next = NULL;
    rec->ion_fd = ion_fd;
    rec->handle = handle;
    rec->buf_fd = buf_fd;
    rec->buf = buf;
    rec->size = size;

    // Insert this record into the list of allocations. Insert it at
    // the front, since it's simpler, and most likely to be freed
    // next.
    pthread_mutex_lock(&allocations_mutex);
    rec->next = allocations.next;
    allocations.next = rec;
    pthread_mutex_unlock(&allocations_mutex);

    return buf;
}

void halide_hexagon_host_free(void *ptr) {
    if (!ptr) {
        return;
    }

    // Find the record for this allocation and remove it from the list.
    pthread_mutex_lock(&allocations_mutex);
    allocation_record *rec = &allocations;
    while (rec) {
        if (rec && rec->next->buf == ptr) {
            allocation_record *before_rec = rec;
            rec = before_rec->next;
            before_rec->next = before_rec->next->next;
            break;
        } else if (rec) {
            rec = rec->next;
        }
    }
    pthread_mutex_unlock(&allocations_mutex);
    if (!rec) {
        __android_log_print(ANDROID_LOG_WARN, "halide", "Allocation not found in allocation records");
        return;
    }

    // Unregister the buffer.
    if (remote_register_buf) {
        remote_register_buf(rec->buf, rec->size, -1);
    }

    // Unmap the memory
    munmap(rec->buf, rec->size);

    // free the ION allocation
    if (ion_free(rec->ion_fd, rec->handle) < 0) {
        __android_log_print(ANDROID_LOG_WARN, "halide", "ion_free(ion_fd, %d) failed", rec->handle);
    }

    // close the ion handle
    close(rec->ion_fd);

    free(rec);
}

// This is a shim for calling v2 from v1.
handle_t halide_hexagon_remote_get_symbol(handle_t module_ptr,
                                          const char* name, int nameLen) {
    handle_t sym = 0;
    int result = halide_hexagon_remote_get_symbol_v2(module_ptr, name, nameLen, &sym);
    return result == 0 ? sym : 0;
}

}  // extern "C"
<commit_msg>Add comments on ION allocator.<commit_after>#include <pthread.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/types.h>
#include <android/log.h>

#include "bin/src/halide_hexagon_remote.h"

namespace {

typedef halide_hexagon_remote_handle_t handle_t;
typedef halide_hexagon_remote_buffer buffer;

// Allocations that are intended to be shared with Hexagon can be
// shared without copying if they are contiguous in physical
// memory. Android's ION allocator gives us a mechanism with which we
// can allocate contiguous physical memory.
typedef int ion_user_handle_t;

struct ion_allocation_data {
    size_t len;
    size_t align;
    unsigned int heap_id_mask;
    unsigned int flags;
    ion_user_handle_t handle;
};

struct ion_fd_data {
    ion_user_handle_t handle;
    int fd;
};

struct ion_handle_data {
    ion_user_handle_t handle;
};

#define ION_IOC_ALLOC _IOWR('I', 0, ion_allocation_data)
#define ION_IOC_FREE _IOWR('I', 1, ion_handle_data)
#define ION_IOC_MAP _IOWR('I', 2, ion_fd_data)

ion_user_handle_t ion_alloc(int ion_fd, size_t len, size_t align, unsigned int heap_id_mask, unsigned int flags) {
    ion_allocation_data alloc = {
        len,
        align,
        heap_id_mask,
        flags,
        0
    };
    if (ioctl(ion_fd, ION_IOC_ALLOC, &alloc) < 0) {
        return -1;
    }
    return alloc.handle;
}

int ion_map(int ion_fd, ion_user_handle_t handle) {
    ion_fd_data data = {
        handle,
        0
    };
    if (ioctl(ion_fd, ION_IOC_MAP, &data) < 0) {
        return -1;
    }
    return data.fd;
}

int ion_free(int ion_fd, ion_user_handle_t ion_handle) {
    if(ioctl(ion_fd, ION_IOC_FREE, &ion_handle) < 0) {
        return -1;
    }
    return 0;
}

// We need to be able to keep track of the size and some other
// information about ION allocations, so define a simple linked list
// of allocations we can traverse later.
struct allocation_record {
    allocation_record *next;
    int ion_fd;
    ion_user_handle_t handle;
    int buf_fd;
    void *buf;
    size_t size;
};

// Make a dummy allocation so we don't need a special case for the
// head list node.
allocation_record allocations = { NULL, };
pthread_mutex_t allocations_mutex;

}  // namespace

extern "C" {

// If this symbol is defined in the stub library we are going to link
// to, we need to call this in order to actually get zero copy
// behavior from our buffers.
__attribute__((weak)) void remote_register_buf(void* buf, int size, int fd);

void halide_hexagon_host_malloc_init() {
    pthread_mutex_init(&allocations_mutex, NULL);
}

void halide_hexagon_host_malloc_deinit() {
    pthread_mutex_destroy(&allocations_mutex);
}

void *halide_hexagon_host_malloc(size_t size) {
    int ion_fd = open("/dev/ion", O_RDONLY, 0);
    if (ion_fd < 0) {
        __android_log_print(ANDROID_LOG_ERROR, "halide", "open('/dev/ion') failed");
        return NULL;
    }

    const int heap_id = 25;  // system heap
    const int ion_flags = 1;  // cached

    // Hexagon can only access a small number of mappings of these
    // sizes. We reduce the number of mappings required by aligning
    // large allocations to these sizes.
    static const size_t alignments[] = { 0x1000, 0x4000, 0x10000, 0x40000, 0x100000 };
    size_t alignment = alignments[0];

    // Align the size up to the minimum alignment.
    size = (size + alignment - 1) & ~(alignment - 1);

    if (heap_id != 25) {
        for (size_t i = 0; i < sizeof(alignments) / sizeof(alignments[0]); i++) {
            if (size >= alignments[i]) {
                alignment = alignments[i];
            }
        }
    }

    ion_user_handle_t handle = ion_alloc(ion_fd, size, alignment, 1 << heap_id, ion_flags);
    if (handle < 0) {
        __android_log_print(ANDROID_LOG_ERROR, "halide", "ion_alloc(ion_fd, %d, %d, %d, %d) failed",
                            size, alignment, 1 << heap_id, ion_flags);
        close(ion_fd);
        return NULL;
    }

    // Map the ion handle to a file buffer.
    int buf_fd = ion_map(ion_fd, handle);
    if (buf_fd < 0) {
        __android_log_print(ANDROID_LOG_ERROR, "halide", "ion_map(ion_fd, %d", handle);
        ion_free(ion_fd, handle);
        close(ion_fd);
        return NULL;
    }

    // Map the file buffer to a pointer.
    void *buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, buf_fd, 0);
    if (buf == MAP_FAILED) {
        __android_log_print(ANDROID_LOG_ERROR, "halide", "mmap(NULL, %d, PROT_READ | PROT_WRITE, MAP_SHARED, %d, 0)",
                            size, buf_fd);
        ion_free(ion_fd, handle);
        close(ion_fd);
        return NULL;
    }

    // Register the buffer, so we get zero copy.
    if (remote_register_buf) {
        remote_register_buf(buf, size, buf_fd);
    }

    // Build a record for this allocation.
    allocation_record *rec = (allocation_record *)malloc(sizeof(allocation_record));
    if (!rec) {
        __android_log_print(ANDROID_LOG_ERROR, "halide", "malloc failed");
        munmap(buf, size);
        ion_free(ion_fd, handle);
        close(ion_fd);
        return NULL;
    }

    rec->next = NULL;
    rec->ion_fd = ion_fd;
    rec->handle = handle;
    rec->buf_fd = buf_fd;
    rec->buf = buf;
    rec->size = size;

    // Insert this record into the list of allocations. Insert it at
    // the front, since it's simpler, and most likely to be freed
    // next.
    pthread_mutex_lock(&allocations_mutex);
    rec->next = allocations.next;
    allocations.next = rec;
    pthread_mutex_unlock(&allocations_mutex);

    return buf;
}

void halide_hexagon_host_free(void *ptr) {
    if (!ptr) {
        return;
    }

    // Find the record for this allocation and remove it from the list.
    pthread_mutex_lock(&allocations_mutex);
    allocation_record *rec = &allocations;
    while (rec) {
        if (rec && rec->next->buf == ptr) {
            allocation_record *before_rec = rec;
            rec = before_rec->next;
            before_rec->next = before_rec->next->next;
            break;
        } else if (rec) {
            rec = rec->next;
        }
    }
    pthread_mutex_unlock(&allocations_mutex);
    if (!rec) {
        __android_log_print(ANDROID_LOG_WARN, "halide", "Allocation not found in allocation records");
        return;
    }

    // Unregister the buffer.
    if (remote_register_buf) {
        remote_register_buf(rec->buf, rec->size, -1);
    }

    // Unmap the memory
    munmap(rec->buf, rec->size);

    // free the ION allocation
    if (ion_free(rec->ion_fd, rec->handle) < 0) {
        __android_log_print(ANDROID_LOG_WARN, "halide", "ion_free(ion_fd, %d) failed", rec->handle);
    }

    // close the ion handle
    close(rec->ion_fd);

    free(rec);
}

// This is a shim for calling v2 from v1.
handle_t halide_hexagon_remote_get_symbol(handle_t module_ptr,
                                          const char* name, int nameLen) {
    handle_t sym = 0;
    int result = halide_hexagon_remote_get_symbol_v2(module_ptr, name, nameLen, &sym);
    return result == 0 ? sym : 0;
}

}  // extern "C"
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "sandboxed_api/sandbox2/stack_trace.h"

#include <dirent.h>

#include <cstdio>
#include <utility>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "sandboxed_api/util/flag.h"
#include "absl/memory/memory.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "sandboxed_api/sandbox2/executor.h"
#include "sandboxed_api/sandbox2/global_forkclient.h"
#include "sandboxed_api/sandbox2/policy.h"
#include "sandboxed_api/sandbox2/policybuilder.h"
#include "sandboxed_api/sandbox2/result.h"
#include "sandboxed_api/sandbox2/sandbox2.h"
#include "sandboxed_api/sandbox2/util/bpf_helper.h"
#include "sandboxed_api/testing.h"
#include "sandboxed_api/util/fileops.h"
#include "sandboxed_api/util/status_matchers.h"
#include "sandboxed_api/util/temp_file.h"

ABSL_DECLARE_FLAG(bool, sandbox_libunwind_crash_handler);

namespace sandbox2 {
namespace {

namespace file_util = ::sapi::file_util;
using ::sapi::CreateNamedTempFileAndClose;
using ::sapi::GetTestSourcePath;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::IsEmpty;
using ::testing::Not;

// Temporarily overrides a flag, restores the original flag value when it goes
// out of scope.
template <typename T>
class TemporaryFlagOverride {
 public:
  using Flag = T;
  TemporaryFlagOverride(Flag* flag, T value)
      : flag_(flag), original_value_(absl::GetFlag(*flag)) {
    absl::SetFlag(flag, value);
  }

  ~TemporaryFlagOverride() { absl::SetFlag(flag_, original_value_); }

 private:
  Flag* flag_;
  T original_value_;
};

// Test that symbolization of stack traces works.
void SymbolizationWorksCommon(
    const std::function<void(PolicyBuilder*)>& modify_policy) {
  const std::string path = GetTestSourcePath("sandbox2/testcases/symbolize");
  std::vector<std::string> args = {path, "1"};
  auto executor = absl::make_unique<Executor>(path, args);

  std::string temp_filename = CreateNamedTempFileAndClose("/tmp/").value();
  file_util::fileops::CopyFile("/proc/cpuinfo", temp_filename, 0444);
  struct TempCleanup {
    ~TempCleanup() { remove(capture->c_str()); }
    std::string* capture;
  } temp_cleanup{&temp_filename};

  PolicyBuilder policybuilder;
  policybuilder
      // Don't restrict the syscalls at all.
      .DangerDefaultAllowAll()
      .AddFile(path)
      .AddLibrariesForBinary(path)
      .AddFileAt(temp_filename, "/proc/cpuinfo");

  modify_policy(&policybuilder);
  SAPI_ASSERT_OK_AND_ASSIGN(auto policy, policybuilder.TryBuild());

  Sandbox2 s2(std::move(executor), std::move(policy));
  auto result = s2.Run();

  ASSERT_THAT(result.final_status(), Eq(Result::SIGNALED));
  ASSERT_THAT(result.GetStackTrace(), HasSubstr("CrashMe"));
  // Check that demangling works as well.
  ASSERT_THAT(result.GetStackTrace(), HasSubstr("CrashMe()"));
}

TEST(StackTraceTest, SymbolizationWorksNonSandboxedLibunwind) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, false);
  SymbolizationWorksCommon([](PolicyBuilder*) {});
}

TEST(StackTraceTest, SymbolizationWorksSandboxedLibunwind) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);
  SymbolizationWorksCommon([](PolicyBuilder*) {});
}

TEST(StackTraceTest, SymbolizationWorksSandboxedLibunwindProcDirMounted) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);
  SymbolizationWorksCommon(
      [](PolicyBuilder* builder) { builder->AddDirectory("/proc"); });
}

TEST(StackTraceTest, SymbolizationWorksSandboxedLibunwindProcFileMounted) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);
  SymbolizationWorksCommon([](PolicyBuilder* builder) {
    builder->AddFile("/proc/sys/vm/overcommit_memory");
  });
}

TEST(StackTraceTest, SymbolizationWorksSandboxedLibunwindSysDirMounted) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);
  SymbolizationWorksCommon(
      [](PolicyBuilder* builder) { builder->AddDirectory("/sys"); });
}

TEST(StackTraceTest, SymbolizationWorksSandboxedLibunwindSysFileMounted) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);
  SymbolizationWorksCommon([](PolicyBuilder* builder) {
    builder->AddFile("/sys/devices/system/cpu/online");
  });
}

static size_t FileCountInDirectory(const std::string& path) {
  std::vector<std::string> fds;
  std::string error;
  CHECK(file_util::fileops::ListDirectoryEntries(path, &fds, &error));
  return fds.size();
}

TEST(StackTraceTest, ForkEnterNsLibunwindDoesNotLeakFDs) {
  SKIP_SANITIZERS_AND_COVERAGE;
  // Get list of open FDs in the global forkserver.
  pid_t forkserver_pid = GlobalForkClient::GetPid();
  std::string forkserver_fd_path =
      absl::StrCat("/proc/", forkserver_pid, "/fd");
  size_t filecount_before = FileCountInDirectory(forkserver_fd_path);

  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);
  SymbolizationWorksCommon([](PolicyBuilder* builder) {
    builder->AddFile("/sys/devices/system/cpu/online");
  });

  EXPECT_THAT(filecount_before, Eq(FileCountInDirectory(forkserver_fd_path)));
}

// Test that symbolization skips writeable files (attack vector).
TEST(StackTraceTest, SymbolizationTrustedFilesOnly) {
  SKIP_SANITIZERS_AND_COVERAGE;
  const std::string path = GetTestSourcePath("sandbox2/testcases/symbolize");
  std::vector<std::string> args = {path, "2"};
  auto executor = absl::make_unique<Executor>(path, args);
  SAPI_ASSERT_OK_AND_ASSIGN(
      auto policy, PolicyBuilder{}  // Don't restrict the syscalls at all.
                       .DangerDefaultAllowAll()
                       .AddFile(path)
                       .AddLibrariesForBinary(path)
                       .TryBuild());

  Sandbox2 s2(std::move(executor), std::move(policy));
  auto result = s2.Run();

  ASSERT_THAT(result.final_status(), Eq(Result::SIGNALED));
  ASSERT_THAT(result.GetStackTrace(), Not(HasSubstr("CrashMe")));
}

TEST(StackTraceTest, CompactStackTrace) {
  EXPECT_THAT(CompactStackTrace({}), IsEmpty());
  EXPECT_THAT(CompactStackTrace({"_start"}), ElementsAre("_start"));
  EXPECT_THAT(CompactStackTrace({
                  "_start",
                  "main",
                  "recursive_call",
                  "recursive_call",
                  "recursive_call",
                  "tail_call",
              }),
              ElementsAre("_start", "main", "recursive_call",
                          "(previous frame repeated 2 times)", "tail_call"));
  EXPECT_THAT(CompactStackTrace({
                  "_start",
                  "main",
                  "recursive_call",
                  "recursive_call",
                  "recursive_call",
                  "recursive_call",
              }),
              ElementsAre("_start", "main", "recursive_call",
                          "(previous frame repeated 3 times)"));
}

}  // namespace
}  // namespace sandbox2
<commit_msg>Fix order-dependent test.<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "sandboxed_api/sandbox2/stack_trace.h"

#include <dirent.h>

#include <cstdio>
#include <utility>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "sandboxed_api/util/flag.h"
#include "absl/memory/memory.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "sandboxed_api/sandbox2/executor.h"
#include "sandboxed_api/sandbox2/global_forkclient.h"
#include "sandboxed_api/sandbox2/policy.h"
#include "sandboxed_api/sandbox2/policybuilder.h"
#include "sandboxed_api/sandbox2/result.h"
#include "sandboxed_api/sandbox2/sandbox2.h"
#include "sandboxed_api/sandbox2/util/bpf_helper.h"
#include "sandboxed_api/testing.h"
#include "sandboxed_api/util/fileops.h"
#include "sandboxed_api/util/status_matchers.h"
#include "sandboxed_api/util/temp_file.h"

ABSL_DECLARE_FLAG(bool, sandbox_libunwind_crash_handler);

namespace sandbox2 {
namespace {

namespace file_util = ::sapi::file_util;
using ::sapi::CreateNamedTempFileAndClose;
using ::sapi::GetTestSourcePath;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::IsEmpty;
using ::testing::Not;

// Temporarily overrides a flag, restores the original flag value when it goes
// out of scope.
template <typename T>
class TemporaryFlagOverride {
 public:
  using Flag = T;
  TemporaryFlagOverride(Flag* flag, T value)
      : flag_(flag), original_value_(absl::GetFlag(*flag)) {
    absl::SetFlag(flag, value);
  }

  ~TemporaryFlagOverride() { absl::SetFlag(flag_, original_value_); }

 private:
  Flag* flag_;
  T original_value_;
};

// Test that symbolization of stack traces works.
void SymbolizationWorksCommon(
    const std::function<void(PolicyBuilder*)>& modify_policy) {
  const std::string path = GetTestSourcePath("sandbox2/testcases/symbolize");
  std::vector<std::string> args = {path, "1"};
  auto executor = absl::make_unique<Executor>(path, args);

  std::string temp_filename = CreateNamedTempFileAndClose("/tmp/").value();
  file_util::fileops::CopyFile("/proc/cpuinfo", temp_filename, 0444);
  struct TempCleanup {
    ~TempCleanup() { remove(capture->c_str()); }
    std::string* capture;
  } temp_cleanup{&temp_filename};

  PolicyBuilder policybuilder;
  policybuilder
      // Don't restrict the syscalls at all.
      .DangerDefaultAllowAll()
      .AddFile(path)
      .AddLibrariesForBinary(path)
      .AddFileAt(temp_filename, "/proc/cpuinfo");

  modify_policy(&policybuilder);
  SAPI_ASSERT_OK_AND_ASSIGN(auto policy, policybuilder.TryBuild());

  Sandbox2 s2(std::move(executor), std::move(policy));
  auto result = s2.Run();

  ASSERT_THAT(result.final_status(), Eq(Result::SIGNALED));
  ASSERT_THAT(result.GetStackTrace(), HasSubstr("CrashMe"));
  // Check that demangling works as well.
  ASSERT_THAT(result.GetStackTrace(), HasSubstr("CrashMe()"));
}

TEST(StackTraceTest, SymbolizationWorksNonSandboxedLibunwind) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, false);
  SymbolizationWorksCommon([](PolicyBuilder*) {});
}

TEST(StackTraceTest, SymbolizationWorksSandboxedLibunwind) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);
  SymbolizationWorksCommon([](PolicyBuilder*) {});
}

TEST(StackTraceTest, SymbolizationWorksSandboxedLibunwindProcDirMounted) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);
  SymbolizationWorksCommon(
      [](PolicyBuilder* builder) { builder->AddDirectory("/proc"); });
}

TEST(StackTraceTest, SymbolizationWorksSandboxedLibunwindProcFileMounted) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);
  SymbolizationWorksCommon([](PolicyBuilder* builder) {
    builder->AddFile("/proc/sys/vm/overcommit_memory");
  });
}

TEST(StackTraceTest, SymbolizationWorksSandboxedLibunwindSysDirMounted) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);
  SymbolizationWorksCommon(
      [](PolicyBuilder* builder) { builder->AddDirectory("/sys"); });
}

TEST(StackTraceTest, SymbolizationWorksSandboxedLibunwindSysFileMounted) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);
  SymbolizationWorksCommon([](PolicyBuilder* builder) {
    builder->AddFile("/sys/devices/system/cpu/online");
  });
}

static size_t FileCountInDirectory(const std::string& path) {
  std::vector<std::string> fds;
  std::string error;
  CHECK(file_util::fileops::ListDirectoryEntries(path, &fds, &error));
  return fds.size();
}

TEST(StackTraceTest, ForkEnterNsLibunwindDoesNotLeakFDs) {
  SKIP_SANITIZERS_AND_COVERAGE;
  TemporaryFlagOverride<bool> temp_override(
      &FLAGS_sandbox_libunwind_crash_handler, true);

  // Very first sanitization might create some fds (e.g. for initial
  // namespaces).
  SymbolizationWorksCommon([](PolicyBuilder* builder) {
    builder->AddFile("/sys/devices/system/cpu/online");
  });

  // Get list of open FDs in the global forkserver.
  pid_t forkserver_pid = GlobalForkClient::GetPid();
  std::string forkserver_fd_path =
      absl::StrCat("/proc/", forkserver_pid, "/fd");
  size_t filecount_before = FileCountInDirectory(forkserver_fd_path);

  SymbolizationWorksCommon([](PolicyBuilder* builder) {
    builder->AddFile("/sys/devices/system/cpu/online");
  });

  EXPECT_THAT(filecount_before, Eq(FileCountInDirectory(forkserver_fd_path)));
}

// Test that symbolization skips writeable files (attack vector).
TEST(StackTraceTest, SymbolizationTrustedFilesOnly) {
  SKIP_SANITIZERS_AND_COVERAGE;
  const std::string path = GetTestSourcePath("sandbox2/testcases/symbolize");
  std::vector<std::string> args = {path, "2"};
  auto executor = absl::make_unique<Executor>(path, args);
  SAPI_ASSERT_OK_AND_ASSIGN(
      auto policy, PolicyBuilder{}  // Don't restrict the syscalls at all.
                       .DangerDefaultAllowAll()
                       .AddFile(path)
                       .AddLibrariesForBinary(path)
                       .TryBuild());

  Sandbox2 s2(std::move(executor), std::move(policy));
  auto result = s2.Run();

  ASSERT_THAT(result.final_status(), Eq(Result::SIGNALED));
  ASSERT_THAT(result.GetStackTrace(), Not(HasSubstr("CrashMe")));
}

TEST(StackTraceTest, CompactStackTrace) {
  EXPECT_THAT(CompactStackTrace({}), IsEmpty());
  EXPECT_THAT(CompactStackTrace({"_start"}), ElementsAre("_start"));
  EXPECT_THAT(CompactStackTrace({
                  "_start",
                  "main",
                  "recursive_call",
                  "recursive_call",
                  "recursive_call",
                  "tail_call",
              }),
              ElementsAre("_start", "main", "recursive_call",
                          "(previous frame repeated 2 times)", "tail_call"));
  EXPECT_THAT(CompactStackTrace({
                  "_start",
                  "main",
                  "recursive_call",
                  "recursive_call",
                  "recursive_call",
                  "recursive_call",
              }),
              ElementsAre("_start", "main", "recursive_call",
                          "(previous frame repeated 3 times)"));
}

}  // namespace
}  // namespace sandbox2
<|endoftext|>


<commit_before>//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the MemoryBuffer interface.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/system_error.h"
#include <cassert>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <new>
#include <sys/stat.h>
#include <sys/types.h>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
#else
#include <io.h>
#ifndef S_ISFIFO
#define S_ISFIFO(x) (0)
#endif
#endif
#include <fcntl.h>
using namespace llvm;

//===----------------------------------------------------------------------===//
// MemoryBuffer implementation itself.
//===----------------------------------------------------------------------===//

MemoryBuffer::~MemoryBuffer() { }

/// init - Initialize this MemoryBuffer as a reference to externally allocated
/// memory, memory that we know is already null terminated.
void MemoryBuffer::init(const char *BufStart, const char *BufEnd,
                        bool RequiresNullTerminator) {
  assert((!RequiresNullTerminator || BufEnd[0] == 0) &&
         "Buffer is not null terminated!");
  BufferStart = BufStart;
  BufferEnd = BufEnd;
}

//===----------------------------------------------------------------------===//
// MemoryBufferMem implementation.
//===----------------------------------------------------------------------===//

/// CopyStringRef - Copies contents of a StringRef into a block of memory and
/// null-terminates it.
static void CopyStringRef(char *Memory, StringRef Data) {
  memcpy(Memory, Data.data(), Data.size());
  Memory[Data.size()] = 0; // Null terminate string.
}

/// GetNamedBuffer - Allocates a new MemoryBuffer with Name copied after it.
template <typename T>
static T *GetNamedBuffer(StringRef Buffer, StringRef Name,
                         bool RequiresNullTerminator) {
  char *Mem = static_cast<char*>(operator new(sizeof(T) + Name.size() + 1));
  CopyStringRef(Mem + sizeof(T), Name);
  return new (Mem) T(Buffer, RequiresNullTerminator);
}

namespace {
/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
class MemoryBufferMem : public MemoryBuffer {
public:
  MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) {
    init(InputData.begin(), InputData.end(), RequiresNullTerminator);
  }

  virtual const char *getBufferIdentifier() const LLVM_OVERRIDE {
     // The name is stored after the class itself.
    return reinterpret_cast<const char*>(this + 1);
  }

  virtual BufferKind getBufferKind() const LLVM_OVERRIDE {
    return MemoryBuffer_Malloc;
  }
};
}

/// getMemBuffer - Open the specified memory range as a MemoryBuffer.  Note
/// that InputData must be a null terminated if RequiresNullTerminator is true!
MemoryBuffer *MemoryBuffer::getMemBuffer(StringRef InputData,
                                         StringRef BufferName,
                                         bool RequiresNullTerminator) {
  return GetNamedBuffer<MemoryBufferMem>(InputData, BufferName,
                                         RequiresNullTerminator);
}

/// getMemBufferCopy - Open the specified memory range as a MemoryBuffer,
/// copying the contents and taking ownership of it.  This has no requirements
/// on EndPtr[0].
MemoryBuffer *MemoryBuffer::getMemBufferCopy(StringRef InputData,
                                             StringRef BufferName) {
  MemoryBuffer *Buf = getNewUninitMemBuffer(InputData.size(), BufferName);
  if (!Buf) return 0;
  memcpy(const_cast<char*>(Buf->getBufferStart()), InputData.data(),
         InputData.size());
  return Buf;
}

/// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size
/// that is not initialized.  Note that the caller should initialize the
/// memory allocated by this method.  The memory is owned by the MemoryBuffer
/// object.
MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(size_t Size,
                                                  StringRef BufferName) {
  // Allocate space for the MemoryBuffer, the data and the name. It is important
  // that MemoryBuffer and data are aligned so PointerIntPair works with them.
  size_t AlignedStringLen =
    RoundUpToAlignment(sizeof(MemoryBufferMem) + BufferName.size() + 1,
                       sizeof(void*)); // TODO: Is sizeof(void*) enough?
  size_t RealLen = AlignedStringLen + Size + 1;
  char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow));
  if (!Mem) return 0;

  // The name is stored after the class itself.
  CopyStringRef(Mem + sizeof(MemoryBufferMem), BufferName);

  // The buffer begins after the name and must be aligned.
  char *Buf = Mem + AlignedStringLen;
  Buf[Size] = 0; // Null terminate buffer.

  return new (Mem) MemoryBufferMem(StringRef(Buf, Size), true);
}

/// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that
/// is completely initialized to zeros.  Note that the caller should
/// initialize the memory allocated by this method.  The memory is owned by
/// the MemoryBuffer object.
MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) {
  MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName);
  if (!SB) return 0;
  memset(const_cast<char*>(SB->getBufferStart()), 0, Size);
  return SB;
}

/// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin
/// if the Filename is "-".  If an error occurs, this returns null and fills
/// in *ErrStr with a reason.  If stdin is empty, this API (unlike getSTDIN)
/// returns an empty buffer.
error_code MemoryBuffer::getFileOrSTDIN(StringRef Filename,
                                        OwningPtr<MemoryBuffer> &result,
                                        int64_t FileSize) {
  if (Filename == "-")
    return getSTDIN(result);
  return getFile(Filename, result, FileSize);
}

error_code MemoryBuffer::getFileOrSTDIN(const char *Filename,
                                        OwningPtr<MemoryBuffer> &result,
                                        int64_t FileSize) {
  if (strcmp(Filename, "-") == 0)
    return getSTDIN(result);
  return getFile(Filename, result, FileSize);
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getFile implementation.
//===----------------------------------------------------------------------===//

namespace {
/// MemoryBufferMMapFile - This represents a file that was mapped in with the
/// sys::Path::MapInFilePages method.  When destroyed, it calls the
/// sys::Path::UnMapFilePages method.
class MemoryBufferMMapFile : public MemoryBufferMem {
public:
  MemoryBufferMMapFile(StringRef Buffer, bool RequiresNullTerminator)
    : MemoryBufferMem(Buffer, RequiresNullTerminator) { }

  ~MemoryBufferMMapFile() {
    static int PageSize = sys::process::get_self()->page_size();

    uintptr_t Start = reinterpret_cast<uintptr_t>(getBufferStart());
    size_t Size = getBufferSize();
    uintptr_t RealStart = Start & ~(PageSize - 1);
    size_t RealSize = Size + (Start - RealStart);

    sys::Path::UnMapFilePages(reinterpret_cast<const char*>(RealStart),
                              RealSize);
  }

  virtual BufferKind getBufferKind() const LLVM_OVERRIDE {
    return MemoryBuffer_MMap;
  }
};
}

static error_code getMemoryBufferForStream(int FD,
                                           StringRef BufferName,
                                           OwningPtr<MemoryBuffer> &result) {
  const ssize_t ChunkSize = 4096*4;
  SmallString<ChunkSize> Buffer;
  ssize_t ReadBytes;
  // Read into Buffer until we hit EOF.
  do {
    Buffer.reserve(Buffer.size() + ChunkSize);
    ReadBytes = read(FD, Buffer.end(), ChunkSize);
    if (ReadBytes == -1) {
      if (errno == EINTR) continue;
      return error_code(errno, posix_category());
    }
    Buffer.set_size(Buffer.size() + ReadBytes);
  } while (ReadBytes != 0);

  result.reset(MemoryBuffer::getMemBufferCopy(Buffer, BufferName));
  return error_code::success();
}

error_code MemoryBuffer::getFile(StringRef Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  // Ensure the path is null terminated.
  SmallString<256> PathBuf(Filename.begin(), Filename.end());
  return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize,
                               RequiresNullTerminator);
}

error_code MemoryBuffer::getFile(const char *Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  // First check that the "file" is not a directory
  bool is_dir = false;
  error_code err = sys::fs::is_directory(Filename, is_dir);
  if (err)
    return err;
  if (is_dir)
    return make_error_code(errc::is_a_directory);

  int OpenFlags = O_RDONLY;
#ifdef O_BINARY
  OpenFlags |= O_BINARY;  // Open input file in binary mode on win32.
#endif
  int FD = ::open(Filename, OpenFlags);
  if (FD == -1)
    return error_code(errno, posix_category());

  error_code ret = getOpenFile(FD, Filename, result, FileSize, FileSize,
                               0, RequiresNullTerminator);
  close(FD);
  return ret;
}

static bool shouldUseMmap(int FD,
                          size_t FileSize,
                          size_t MapSize,
                          off_t Offset,
                          bool RequiresNullTerminator,
                          int PageSize) {
  // We don't use mmap for small files because this can severely fragment our
  // address space.
  if (MapSize < 4096*4)
    return false;

  if (!RequiresNullTerminator)
    return true;

  // If we don't know the file size, use fstat to find out.  fstat on an open
  // file descriptor is cheaper than stat on a random path.
  // FIXME: this chunk of code is duplicated, but it avoids a fstat when
  // RequiresNullTerminator = false and MapSize != -1.
  if (FileSize == size_t(-1)) {
    struct stat FileInfo;
    // TODO: This should use fstat64 when available.
    if (fstat(FD, &FileInfo) == -1) {
      return error_code(errno, posix_category());
    }
    FileSize = FileInfo.st_size;
  }

  // If we need a null terminator and the end of the map is inside the file,
  // we cannot use mmap.
  size_t End = Offset + MapSize;
  assert(End <= FileSize);
  if (End != FileSize)
    return false;

  // Don't try to map files that are exactly a multiple of the system page size
  // if we need a null terminator.
  if ((FileSize & (PageSize -1)) == 0)
    return false;

  return true;
}

error_code MemoryBuffer::getOpenFile(int FD, const char *Filename,
                                     OwningPtr<MemoryBuffer> &result,
                                     uint64_t FileSize, uint64_t MapSize,
                                     int64_t Offset,
                                     bool RequiresNullTerminator) {
  static int PageSize = sys::process::get_self()->page_size();

  // Default is to map the full file.
  if (MapSize == uint64_t(-1)) {
    // If we don't know the file size, use fstat to find out.  fstat on an open
    // file descriptor is cheaper than stat on a random path.
    if (FileSize == uint64_t(-1)) {
      struct stat FileInfo;
      // TODO: This should use fstat64 when available.
      if (fstat(FD, &FileInfo) == -1) {
        return error_code(errno, posix_category());
      }

      // If this is a named pipe, we can't trust the size. Create the memory
      // buffer by copying off the stream.
      if (S_ISFIFO(FileInfo.st_mode)) {
        return getMemoryBufferForStream(FD, Filename, result);
      }

      FileSize = FileInfo.st_size;
    }
    MapSize = FileSize;
  }

  if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator,
                    PageSize)) {
    off_t RealMapOffset = Offset & ~(PageSize - 1);
    off_t Delta = Offset - RealMapOffset;
    size_t RealMapSize = MapSize + Delta;

    if (const char *Pages = sys::Path::MapInFilePages(FD,
                                                      RealMapSize,
                                                      RealMapOffset)) {
      result.reset(GetNamedBuffer<MemoryBufferMMapFile>(
          StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator));
      return error_code::success();
    }
  }

  MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename);
  if (!Buf) {
    // Failed to create a buffer. The only way it can fail is if
    // new(std::nothrow) returns 0.
    return make_error_code(errc::not_enough_memory);
  }

  OwningPtr<MemoryBuffer> SB(Buf);
  char *BufPtr = const_cast<char*>(SB->getBufferStart());

  size_t BytesLeft = MapSize;
#ifndef HAVE_PREAD
  if (lseek(FD, Offset, SEEK_SET) == -1)
    return error_code(errno, posix_category());
#endif

  while (BytesLeft) {
#ifdef HAVE_PREAD
    ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset);
#else
    ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
#endif
    if (NumRead == -1) {
      if (errno == EINTR)
        continue;
      // Error while reading.
      return error_code(errno, posix_category());
    }
    if (NumRead == 0) {
      assert(0 && "We got inaccurate FileSize value or fstat reported an "
                   "invalid file size.");
      *BufPtr = '\0'; // null-terminate at the actual size.
      break;
    }
    BytesLeft -= NumRead;
    BufPtr += NumRead;
  }

  result.swap(SB);
  return error_code::success();
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getSTDIN implementation.
//===----------------------------------------------------------------------===//

error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) {
  // Read in all of the data from stdin, we cannot mmap stdin.
  //
  // FIXME: That isn't necessarily true, we should try to mmap stdin and
  // fallback if it fails.
  sys::Program::ChangeStdinToBinary();

  return getMemoryBufferForStream(0, "<stdin>", result);
}
<commit_msg>Don't trust st_size of a character device. This fixes using /dev/stdin as an input when stdin is connected to a tty, for example.<commit_after>//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the MemoryBuffer interface.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/system_error.h"
#include <cassert>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <new>
#include <sys/stat.h>
#include <sys/types.h>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
#else
#include <io.h>
#ifndef S_ISFIFO
#define S_ISFIFO(x) (0)
#endif
#endif
#include <fcntl.h>
using namespace llvm;

//===----------------------------------------------------------------------===//
// MemoryBuffer implementation itself.
//===----------------------------------------------------------------------===//

MemoryBuffer::~MemoryBuffer() { }

/// init - Initialize this MemoryBuffer as a reference to externally allocated
/// memory, memory that we know is already null terminated.
void MemoryBuffer::init(const char *BufStart, const char *BufEnd,
                        bool RequiresNullTerminator) {
  assert((!RequiresNullTerminator || BufEnd[0] == 0) &&
         "Buffer is not null terminated!");
  BufferStart = BufStart;
  BufferEnd = BufEnd;
}

//===----------------------------------------------------------------------===//
// MemoryBufferMem implementation.
//===----------------------------------------------------------------------===//

/// CopyStringRef - Copies contents of a StringRef into a block of memory and
/// null-terminates it.
static void CopyStringRef(char *Memory, StringRef Data) {
  memcpy(Memory, Data.data(), Data.size());
  Memory[Data.size()] = 0; // Null terminate string.
}

/// GetNamedBuffer - Allocates a new MemoryBuffer with Name copied after it.
template <typename T>
static T *GetNamedBuffer(StringRef Buffer, StringRef Name,
                         bool RequiresNullTerminator) {
  char *Mem = static_cast<char*>(operator new(sizeof(T) + Name.size() + 1));
  CopyStringRef(Mem + sizeof(T), Name);
  return new (Mem) T(Buffer, RequiresNullTerminator);
}

namespace {
/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
class MemoryBufferMem : public MemoryBuffer {
public:
  MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) {
    init(InputData.begin(), InputData.end(), RequiresNullTerminator);
  }

  virtual const char *getBufferIdentifier() const LLVM_OVERRIDE {
     // The name is stored after the class itself.
    return reinterpret_cast<const char*>(this + 1);
  }

  virtual BufferKind getBufferKind() const LLVM_OVERRIDE {
    return MemoryBuffer_Malloc;
  }
};
}

/// getMemBuffer - Open the specified memory range as a MemoryBuffer.  Note
/// that InputData must be a null terminated if RequiresNullTerminator is true!
MemoryBuffer *MemoryBuffer::getMemBuffer(StringRef InputData,
                                         StringRef BufferName,
                                         bool RequiresNullTerminator) {
  return GetNamedBuffer<MemoryBufferMem>(InputData, BufferName,
                                         RequiresNullTerminator);
}

/// getMemBufferCopy - Open the specified memory range as a MemoryBuffer,
/// copying the contents and taking ownership of it.  This has no requirements
/// on EndPtr[0].
MemoryBuffer *MemoryBuffer::getMemBufferCopy(StringRef InputData,
                                             StringRef BufferName) {
  MemoryBuffer *Buf = getNewUninitMemBuffer(InputData.size(), BufferName);
  if (!Buf) return 0;
  memcpy(const_cast<char*>(Buf->getBufferStart()), InputData.data(),
         InputData.size());
  return Buf;
}

/// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size
/// that is not initialized.  Note that the caller should initialize the
/// memory allocated by this method.  The memory is owned by the MemoryBuffer
/// object.
MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(size_t Size,
                                                  StringRef BufferName) {
  // Allocate space for the MemoryBuffer, the data and the name. It is important
  // that MemoryBuffer and data are aligned so PointerIntPair works with them.
  size_t AlignedStringLen =
    RoundUpToAlignment(sizeof(MemoryBufferMem) + BufferName.size() + 1,
                       sizeof(void*)); // TODO: Is sizeof(void*) enough?
  size_t RealLen = AlignedStringLen + Size + 1;
  char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow));
  if (!Mem) return 0;

  // The name is stored after the class itself.
  CopyStringRef(Mem + sizeof(MemoryBufferMem), BufferName);

  // The buffer begins after the name and must be aligned.
  char *Buf = Mem + AlignedStringLen;
  Buf[Size] = 0; // Null terminate buffer.

  return new (Mem) MemoryBufferMem(StringRef(Buf, Size), true);
}

/// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that
/// is completely initialized to zeros.  Note that the caller should
/// initialize the memory allocated by this method.  The memory is owned by
/// the MemoryBuffer object.
MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) {
  MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName);
  if (!SB) return 0;
  memset(const_cast<char*>(SB->getBufferStart()), 0, Size);
  return SB;
}

/// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin
/// if the Filename is "-".  If an error occurs, this returns null and fills
/// in *ErrStr with a reason.  If stdin is empty, this API (unlike getSTDIN)
/// returns an empty buffer.
error_code MemoryBuffer::getFileOrSTDIN(StringRef Filename,
                                        OwningPtr<MemoryBuffer> &result,
                                        int64_t FileSize) {
  if (Filename == "-")
    return getSTDIN(result);
  return getFile(Filename, result, FileSize);
}

error_code MemoryBuffer::getFileOrSTDIN(const char *Filename,
                                        OwningPtr<MemoryBuffer> &result,
                                        int64_t FileSize) {
  if (strcmp(Filename, "-") == 0)
    return getSTDIN(result);
  return getFile(Filename, result, FileSize);
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getFile implementation.
//===----------------------------------------------------------------------===//

namespace {
/// MemoryBufferMMapFile - This represents a file that was mapped in with the
/// sys::Path::MapInFilePages method.  When destroyed, it calls the
/// sys::Path::UnMapFilePages method.
class MemoryBufferMMapFile : public MemoryBufferMem {
public:
  MemoryBufferMMapFile(StringRef Buffer, bool RequiresNullTerminator)
    : MemoryBufferMem(Buffer, RequiresNullTerminator) { }

  ~MemoryBufferMMapFile() {
    static int PageSize = sys::process::get_self()->page_size();

    uintptr_t Start = reinterpret_cast<uintptr_t>(getBufferStart());
    size_t Size = getBufferSize();
    uintptr_t RealStart = Start & ~(PageSize - 1);
    size_t RealSize = Size + (Start - RealStart);

    sys::Path::UnMapFilePages(reinterpret_cast<const char*>(RealStart),
                              RealSize);
  }

  virtual BufferKind getBufferKind() const LLVM_OVERRIDE {
    return MemoryBuffer_MMap;
  }
};
}

static error_code getMemoryBufferForStream(int FD,
                                           StringRef BufferName,
                                           OwningPtr<MemoryBuffer> &result) {
  const ssize_t ChunkSize = 4096*4;
  SmallString<ChunkSize> Buffer;
  ssize_t ReadBytes;
  // Read into Buffer until we hit EOF.
  do {
    Buffer.reserve(Buffer.size() + ChunkSize);
    ReadBytes = read(FD, Buffer.end(), ChunkSize);
    if (ReadBytes == -1) {
      if (errno == EINTR) continue;
      return error_code(errno, posix_category());
    }
    Buffer.set_size(Buffer.size() + ReadBytes);
  } while (ReadBytes != 0);

  result.reset(MemoryBuffer::getMemBufferCopy(Buffer, BufferName));
  return error_code::success();
}

error_code MemoryBuffer::getFile(StringRef Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  // Ensure the path is null terminated.
  SmallString<256> PathBuf(Filename.begin(), Filename.end());
  return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize,
                               RequiresNullTerminator);
}

error_code MemoryBuffer::getFile(const char *Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  // First check that the "file" is not a directory
  bool is_dir = false;
  error_code err = sys::fs::is_directory(Filename, is_dir);
  if (err)
    return err;
  if (is_dir)
    return make_error_code(errc::is_a_directory);

  int OpenFlags = O_RDONLY;
#ifdef O_BINARY
  OpenFlags |= O_BINARY;  // Open input file in binary mode on win32.
#endif
  int FD = ::open(Filename, OpenFlags);
  if (FD == -1)
    return error_code(errno, posix_category());

  error_code ret = getOpenFile(FD, Filename, result, FileSize, FileSize,
                               0, RequiresNullTerminator);
  close(FD);
  return ret;
}

static bool shouldUseMmap(int FD,
                          size_t FileSize,
                          size_t MapSize,
                          off_t Offset,
                          bool RequiresNullTerminator,
                          int PageSize) {
  // We don't use mmap for small files because this can severely fragment our
  // address space.
  if (MapSize < 4096*4)
    return false;

  if (!RequiresNullTerminator)
    return true;

  // If we don't know the file size, use fstat to find out.  fstat on an open
  // file descriptor is cheaper than stat on a random path.
  // FIXME: this chunk of code is duplicated, but it avoids a fstat when
  // RequiresNullTerminator = false and MapSize != -1.
  if (FileSize == size_t(-1)) {
    struct stat FileInfo;
    // TODO: This should use fstat64 when available.
    if (fstat(FD, &FileInfo) == -1) {
      return error_code(errno, posix_category());
    }
    FileSize = FileInfo.st_size;
  }

  // If we need a null terminator and the end of the map is inside the file,
  // we cannot use mmap.
  size_t End = Offset + MapSize;
  assert(End <= FileSize);
  if (End != FileSize)
    return false;

  // Don't try to map files that are exactly a multiple of the system page size
  // if we need a null terminator.
  if ((FileSize & (PageSize -1)) == 0)
    return false;

  return true;
}

error_code MemoryBuffer::getOpenFile(int FD, const char *Filename,
                                     OwningPtr<MemoryBuffer> &result,
                                     uint64_t FileSize, uint64_t MapSize,
                                     int64_t Offset,
                                     bool RequiresNullTerminator) {
  static int PageSize = sys::process::get_self()->page_size();

  // Default is to map the full file.
  if (MapSize == uint64_t(-1)) {
    // If we don't know the file size, use fstat to find out.  fstat on an open
    // file descriptor is cheaper than stat on a random path.
    if (FileSize == uint64_t(-1)) {
      struct stat FileInfo;
      // TODO: This should use fstat64 when available.
      if (fstat(FD, &FileInfo) == -1) {
        return error_code(errno, posix_category());
      }

      // If this is a named pipe or character device, we can't trust the size.
      // Create the memory buffer by copying off the stream.
      if (S_ISFIFO(FileInfo.st_mode) || S_ISCHR(FileInfo.st_mode)) {
        return getMemoryBufferForStream(FD, Filename, result);
      }

      FileSize = FileInfo.st_size;
    }
    MapSize = FileSize;
  }

  if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator,
                    PageSize)) {
    off_t RealMapOffset = Offset & ~(PageSize - 1);
    off_t Delta = Offset - RealMapOffset;
    size_t RealMapSize = MapSize + Delta;

    if (const char *Pages = sys::Path::MapInFilePages(FD,
                                                      RealMapSize,
                                                      RealMapOffset)) {
      result.reset(GetNamedBuffer<MemoryBufferMMapFile>(
          StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator));
      return error_code::success();
    }
  }

  MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename);
  if (!Buf) {
    // Failed to create a buffer. The only way it can fail is if
    // new(std::nothrow) returns 0.
    return make_error_code(errc::not_enough_memory);
  }

  OwningPtr<MemoryBuffer> SB(Buf);
  char *BufPtr = const_cast<char*>(SB->getBufferStart());

  size_t BytesLeft = MapSize;
#ifndef HAVE_PREAD
  if (lseek(FD, Offset, SEEK_SET) == -1)
    return error_code(errno, posix_category());
#endif

  while (BytesLeft) {
#ifdef HAVE_PREAD
    ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset);
#else
    ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
#endif
    if (NumRead == -1) {
      if (errno == EINTR)
        continue;
      // Error while reading.
      return error_code(errno, posix_category());
    }
    if (NumRead == 0) {
      assert(0 && "We got inaccurate FileSize value or fstat reported an "
                   "invalid file size.");
      *BufPtr = '\0'; // null-terminate at the actual size.
      break;
    }
    BytesLeft -= NumRead;
    BufPtr += NumRead;
  }

  result.swap(SB);
  return error_code::success();
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getSTDIN implementation.
//===----------------------------------------------------------------------===//

error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) {
  // Read in all of the data from stdin, we cannot mmap stdin.
  //
  // FIXME: That isn't necessarily true, we should try to mmap stdin and
  // fallback if it fails.
  sys::Program::ChangeStdinToBinary();

  return getMemoryBufferForStream(0, "<stdin>", result);
}
<|endoftext|>


<commit_before>
#include "AutoPilot.h"
#include "coilBoard.h"
#include "wheelcontroller.h"
#include <thread>

std::pair<DriveMode, std::string> DriveModes[] = {
	std::pair<DriveMode, std::string>(IDLE, "IDLE"),
	std::pair<DriveMode, std::string>(LOCATE_BALL, "LOCATE_BALL"),
	std::pair<DriveMode, std::string>(DRIVE_TO_BALL, "DRIVE_TO_BALL"),
	std::pair<DriveMode, std::string>(LOCATE_GATE, "LOCATE_GATE"),
	std::pair<DriveMode, std::string>(CATCH_BALL, "CATCH_BALL"),
	std::pair<DriveMode, std::string>(RECOVER_CRASH, "RECOVER_CRASH"),

	//	std::pair<STATE, std::string>(STATE_END_OF_GAME, "End of Game") // this is intentionally left out

};

std::map<DriveMode, std::string> DRIVEMODE_LABELS(DriveModes, DriveModes + sizeof(DriveModes) / sizeof(DriveModes[0]));

AutoPilot::AutoPilot(WheelController *wheels, CoilGun *coilgun) :wheels(wheels), coilgun(coilgun)
{
	stop_thread = false;
	threads.create_thread(boost::bind(&AutoPilot::Run, this));
}

void AutoPilot::UpdateState(ObjectPosition *ballLocation, ObjectPosition *gateLocation)
{
	boost::mutex::scoped_lock lock(mutex);
	ballInSight = ballLocation != NULL;
	gateInSight = gateLocation != NULL;
	if (ballInSight) lastBallLocation = *ballLocation;
	if (gateInSight) lastGateLocation = *gateLocation;
	ballInTribbler =  coilgun->BallInTribbler();
	lastUpdate = boost::posix_time::microsec_clock::local_time();
	if (driveMode == IDLE) driveMode = LOCATE_BALL;
}

/*
No ball in sight
*/
DriveMode AutoPilot::LocateBall() {
	if (coilgun->BallInTribbler()){
		return LOCATE_GATE;
	}

	if (ballInSight) return DRIVE_TO_BALL;
	boost::posix_time::ptime time = boost::posix_time::microsec_clock::local_time();
	boost::posix_time::ptime rotateStart = time;
	boost::posix_time::ptime rotateTime = time;
	while (!ballInSight) {
		if (coilgun->BallInTribbler()){
			return LOCATE_GATE;
		}
		if (stop_thread) return EXIT;
		if ((boost::posix_time::microsec_clock::local_time() - lastUpdate).total_milliseconds() > 1000) return IDLE;

		if (wheels->IsStalled()) return RECOVER_CRASH;

		time = boost::posix_time::microsec_clock::local_time();
		if ((time - rotateStart).total_milliseconds() > 10000) { // give up after 10 sec or perhaps go to different search mode
			return IDLE;
		}
		boost::posix_time::time_duration::tick_type rotateDuration = (time - rotateTime).total_milliseconds();
		if (false && rotateDuration >= 500){
			wheels->Stop();
			if (rotateDuration >= 600){
				rotateTime = time; //reset
			}
		}
		else{
			wheels->Rotate(1, 10);
		}

		std::chrono::milliseconds dura(10);
		std::this_thread::sleep_for(dura);
	}
	return DRIVE_TO_BALL;
}

DriveMode AutoPilot::DriveToBall()
{
	double speed;
	double rotate;
	double rotateGate;
	int desiredDistance = 280;

	while (true) {
		if (stop_thread) return EXIT;
		if ((boost::posix_time::microsec_clock::local_time() - lastUpdate).total_milliseconds() > 1000) return IDLE;

		if (wheels->IsStalled()) return RECOVER_CRASH;

		//rotate calculation for ball
		if (lastBallLocation.horizontalAngle > 200){
			rotate = (360 - lastBallLocation.horizontalAngle) *0.5;
		}
		else{
			rotate = lastBallLocation.horizontalAngle * 0.5;
		}

		//driving commands

		//if ball is close and  center
		if (lastBallLocation.distance < desiredDistance &&
			lastBallLocation.horizontalDev < -10 &&
			lastBallLocation.horizontalDev > 10){

				coilgun->ToggleTribbler(true);
				return CATCH_BALL;

			}
		//if ball is close and not center
		else if (lastBallLocation.distance <= desiredDistance){
			coilgun->ToggleTribbler(true);
			if (lastBallLocation.horizontalDev < -10) {
				wheels->Rotate(1, rotate);
			}
			else if (lastBallLocation.horizontalDev > 10) {
				wheels->Rotate(0, rotate);
			}
		}
		//if ball is not close
		else {
			coilgun->ToggleTribbler(false);
			//speed calculation
			if (lastBallLocation.distance > 700){
				speed = 150;
			}
			else{
				speed = lastBallLocation.distance * 0.33 -77;
			}
			//Which way to rotate
			if(lastBallLocation.horizontalAngle > 200){
				wheels->DriveRotate(speed, lastBallLocation.horizontalAngle, -rotate);
			}
			else{
				wheels->DriveRotate(speed, lastBallLocation.horizontalAngle, rotate);
			}
		}

		//check tribbler
		if (coilgun->BallInTribbler()){
			return LOCATE_GATE;
		}
	}
}

DriveMode AutoPilot::CatchBall(){
	boost::posix_time::ptime time = boost::posix_time::microsec_clock::local_time();
	boost::posix_time::ptime catchStart = time;
	boost::posix_time::time_duration::tick_type catchDuration = (time - catchStart).total_milliseconds();
	bool inTribbler = coilgun->BallInTribbler();
	//trying to catch ball for 2 seconds
	while (!inTribbler && catchDuration < 2000){
		if (stop_thread) return EXIT;
		catchDuration = (time - catchStart).total_milliseconds();
		time = boost::posix_time::microsec_clock::local_time();
		coilgun->ToggleTribbler(true);//start tribbler
		wheels->Forward(15);
		inTribbler = coilgun->BallInTribbler();
	}
	if (inTribbler){
		return LOCATE_GATE;
	}
	else{
		return LOCATE_BALL;
	}
}

DriveMode AutoPilot::LocateGate() {

	boost::posix_time::ptime time = boost::posix_time::microsec_clock::local_time();
	boost::posix_time::ptime rotateStart = time;
	boost::posix_time::ptime rotateTime = time;
	while (!gateInSight) {
		coilgun->ToggleTribbler(true);
		if (stop_thread) return EXIT;
		if ((boost::posix_time::microsec_clock::local_time() - lastUpdate).total_milliseconds() > 1000) return IDLE;

		if (!coilgun->BallInTribbler()) return DRIVE_TO_BALL;
		if (wheels->IsStalled()) return RECOVER_CRASH;

		time = boost::posix_time::microsec_clock::local_time();
		if ((time - rotateStart).total_milliseconds() > 10000) { // give up after 10 sec or perhaps go to different search mode
			return IDLE;
		}
		boost::posix_time::time_duration::tick_type rotateDuration = (time - rotateTime).total_milliseconds();
		if (false && rotateDuration >= 500){
			wheels->Stop();
			if (rotateDuration >= 600){
				rotateTime = time; //reset
			}
		}
		else{
			wheels->Rotate(1, 10);
		}
		std::chrono::milliseconds dura(8);
		std::this_thread::sleep_for(dura);
	}
	while(gateInSight ){
		if (stop_thread) return EXIT;
		if (lastGateLocation.horizontalDev > -50 && lastGateLocation.horizontalDev < 50){
			coilgun->ToggleTribbler(false);
			wheels->Stop();
			std::chrono::milliseconds dura(50);
			std::this_thread::sleep_for(dura);
			coilgun->Kick();
			return LOCATE_BALL;
		}
		else if(lastGateLocation.horizontalDev < -50){
			wheels->Rotate(0, 10);
		}
		else{
			wheels->Rotate(1, 10);
		}
	}

}

DriveMode AutoPilot::RecoverCrash()
{
	while (wheels->IsStalled()) {
		//Backwards
		wheels->Drive(50, 180);
		std::chrono::milliseconds dura(1000);
		std::this_thread::sleep_for(dura);
		wheels->Stop();
		//Turn a littlebit
		wheels->Rotate(1, 20);
		std::this_thread::sleep_for(dura);
		wheels->Stop();
	}
	return LOCATE_BALL;
}

void AutoPilot::Run()
{

	while (!stop_thread){
		WriteInfoOnScreen();
		switch (driveMode){
		case IDLE:
			std::this_thread::sleep_for(std::chrono::milliseconds(100));
			break;
		case LOCATE_BALL:
			driveMode = LocateBall();
			break;
		case DRIVE_TO_BALL:
			driveMode = DriveToBall();
			break;
		case CATCH_BALL:
			driveMode = CatchBall();
		case LOCATE_GATE:
			driveMode = LocateGate();
			break;
		case RECOVER_CRASH:
			driveMode = RecoverCrash();
			break;
		case EXIT:
			stop_thread = true;
		}
		std::chrono::milliseconds dura(8);
		std::this_thread::sleep_for(dura);
	}
}

void AutoPilot::WriteInfoOnScreen(){
	cv::Mat infoWindow(140, 250, CV_8UC3, cv::Scalar::all(0));
	std::ostringstream oss;
	oss << "State :" << DRIVEMODE_LABELS[driveMode];
	cv::putText(infoWindow, oss.str(), cv::Point(20, 20), cv::FONT_HERSHEY_DUPLEX, 0.5, cv::Scalar(255, 255, 255));
	oss.str("");
	oss << "Ball visible :" << (ballInSight ? "yes" : "no");
	cv::putText(infoWindow, oss.str(), cv::Point(20, 50), cv::FONT_HERSHEY_DUPLEX, 0.5, cv::Scalar(255, 255, 255));
	oss.str("");
	oss << "Gate Visible :" << (gateInSight ? "yes" : "no");
	cv::putText(infoWindow, oss.str(), cv::Point(20, 80), cv::FONT_HERSHEY_DUPLEX, 0.5, cv::Scalar(255, 255, 255));
	oss.str("");
	oss << "Ball in tribbler :" << (ballInTribbler ? "yes" : "no");
	cv::putText(infoWindow, oss.str(), cv::Point(20, 110), cv::FONT_HERSHEY_DUPLEX, 0.5, cv::Scalar(255, 255, 255));
	cv::imshow("AutoPilot", infoWindow);
	cv::waitKey(1);
	return;
}

AutoPilot::~AutoPilot()
{
	coilgun->ToggleTribbler(false);
	stop_thread = true;
	threads.join_all();

}
<commit_msg>Gate searching changes.<commit_after>
#include "AutoPilot.h"
#include "coilBoard.h"
#include "wheelcontroller.h"
#include <thread>

std::pair<DriveMode, std::string> DriveModes[] = {
	std::pair<DriveMode, std::string>(IDLE, "IDLE"),
	std::pair<DriveMode, std::string>(LOCATE_BALL, "LOCATE_BALL"),
	std::pair<DriveMode, std::string>(DRIVE_TO_BALL, "DRIVE_TO_BALL"),
	std::pair<DriveMode, std::string>(LOCATE_GATE, "LOCATE_GATE"),
	std::pair<DriveMode, std::string>(CATCH_BALL, "CATCH_BALL"),
	std::pair<DriveMode, std::string>(RECOVER_CRASH, "RECOVER_CRASH"),

	//	std::pair<STATE, std::string>(STATE_END_OF_GAME, "End of Game") // this is intentionally left out

};

std::map<DriveMode, std::string> DRIVEMODE_LABELS(DriveModes, DriveModes + sizeof(DriveModes) / sizeof(DriveModes[0]));

AutoPilot::AutoPilot(WheelController *wheels, CoilGun *coilgun) :wheels(wheels), coilgun(coilgun)
{
	stop_thread = false;
	threads.create_thread(boost::bind(&AutoPilot::Run, this));
}

void AutoPilot::UpdateState(ObjectPosition *ballLocation, ObjectPosition *gateLocation)
{
	boost::mutex::scoped_lock lock(mutex);
	ballInSight = ballLocation != NULL;
	gateInSight = gateLocation != NULL;
	if (ballInSight) lastBallLocation = *ballLocation;
	if (gateInSight) lastGateLocation = *gateLocation;
	ballInTribbler =  coilgun->BallInTribbler();
	lastUpdate = boost::posix_time::microsec_clock::local_time();
	if (driveMode == IDLE) driveMode = LOCATE_BALL;
}

/*
No ball in sight
*/
DriveMode AutoPilot::LocateBall() {
	if (coilgun->BallInTribbler()){
		return LOCATE_GATE;
	}

	if (ballInSight) return DRIVE_TO_BALL;
	boost::posix_time::ptime time = boost::posix_time::microsec_clock::local_time();
	boost::posix_time::ptime rotateStart = time;
	boost::posix_time::ptime rotateTime = time;
	while (!ballInSight) {
		if (coilgun->BallInTribbler()){
			return LOCATE_GATE;
		}
		if (stop_thread) return EXIT;
		if ((boost::posix_time::microsec_clock::local_time() - lastUpdate).total_milliseconds() > 1000) return IDLE;

		if (wheels->IsStalled()) return RECOVER_CRASH;

		time = boost::posix_time::microsec_clock::local_time();
		if ((time - rotateStart).total_milliseconds() > 10000) { // give up after 10 sec or perhaps go to different search mode
			return IDLE;
		}
		boost::posix_time::time_duration::tick_type rotateDuration = (time - rotateTime).total_milliseconds();
		if (false && rotateDuration >= 500){
			wheels->Stop();
			if (rotateDuration >= 600){
				rotateTime = time; //reset
			}
		}
		else{
			wheels->Rotate(1, 10);
		}

		std::chrono::milliseconds dura(10);
		std::this_thread::sleep_for(dura);
	}
	return DRIVE_TO_BALL;
}

DriveMode AutoPilot::DriveToBall()
{
	double speed;
	double rotate;
	double rotateGate;
	int desiredDistance = 280;

	while (true) {
		if (stop_thread) return EXIT;
		if ((boost::posix_time::microsec_clock::local_time() - lastUpdate).total_milliseconds() > 1000) return IDLE;

		if (wheels->IsStalled()) return RECOVER_CRASH;

		//rotate calculation for ball
		if (lastBallLocation.horizontalAngle > 200){
			rotate = (360 - lastBallLocation.horizontalAngle) * 0.4 + 5;
		}
		else{
			rotate = lastBallLocation.horizontalAngle  * 0.4 + 5;
		}

		//driving commands

		//if ball is close and  center
		if (lastBallLocation.distance < desiredDistance &&
			lastBallLocation.horizontalDev < -10 &&
			lastBallLocation.horizontalDev > 10){

				wheels->StopWheels();
				coilgun->ToggleTribbler(true);
				return CATCH_BALL;

			}
		//if ball is close and not center
		else if (lastBallLocation.distance <= desiredDistance){
			coilgun->ToggleTribbler(true);
			if (lastBallLocation.horizontalDev < -10) {
				wheels->Rotate(1, rotate);
			}
			else if (lastBallLocation.horizontalDev > 10) {
				wheels->Rotate(0, rotate);
			}
		}
		//if ball is not close
		else {
			coilgun->ToggleTribbler(false);
			//speed calculation
			if (lastBallLocation.distance > 700){
				speed = 150;
			}
			else{
				speed = lastBallLocation.distance * 0.33 -77;
			}
			//Which way to rotate
			if(lastBallLocation.horizontalAngle > 200){
				wheels->DriveRotate(speed, lastBallLocation.horizontalAngle, -rotate);
			}
			else{
				wheels->DriveRotate(speed, lastBallLocation.horizontalAngle, rotate);
			}
		}

		//check tribbler
		if (coilgun->BallInTribbler()){
			return LOCATE_GATE;
		}
	}
}

DriveMode AutoPilot::CatchBall(){
	boost::posix_time::ptime time = boost::posix_time::microsec_clock::local_time();
	boost::posix_time::ptime catchStart = time;
	boost::posix_time::time_duration::tick_type catchDuration = (time - catchStart).total_milliseconds();
	bool inTribbler = coilgun->BallInTribbler();
	//trying to catch ball for 2 seconds
	while (!inTribbler && catchDuration < 2000){
		if (stop_thread) return EXIT;
		catchDuration = (time - catchStart).total_milliseconds();
		time = boost::posix_time::microsec_clock::local_time();
		coilgun->ToggleTribbler(true);//start tribbler
		wheels->Forward(15);
		inTribbler = coilgun->BallInTribbler();
	}
	if (inTribbler){
		return LOCATE_GATE;
	}
	else{
		return LOCATE_BALL;
	}
}

DriveMode AutoPilot::LocateGate() {

	boost::posix_time::ptime time = boost::posix_time::microsec_clock::local_time();
	boost::posix_time::ptime rotateStart = time;
	boost::posix_time::ptime rotateTime = time;
	while (true){
		//Search
		while (!gateInSight) {
			coilgun->ToggleTribbler(true);
			if (stop_thread) return EXIT;
			if ((boost::posix_time::microsec_clock::local_time() - lastUpdate).total_milliseconds() > 1000) return IDLE;

			if (wheels->IsStalled()) return RECOVER_CRASH;

			time = boost::posix_time::microsec_clock::local_time();
			if ((time - rotateStart).total_milliseconds() > 10000) { // give up after 10 sec or perhaps go to different search mode
				return IDLE;
			}
			boost::posix_time::time_duration::tick_type rotateDuration = (time - rotateTime).total_milliseconds();
			if (false && rotateDuration >= 500){
				wheels->Stop();
				if (rotateDuration >= 600){
					rotateTime = time; //reset
				}
			}
			else{
				wheels->Rotate(1, 10);
			}
			std::chrono::milliseconds dura(8);
			std::this_thread::sleep_for(dura);
		}
		//Aim
		while (gateInSight){
			if (stop_thread) return EXIT;
			//rotate calculation for gate
			if (lastGateLocation.horizontalAngle > 200){
				int rotate = (360 - lastGateLocation.horizontalAngle) * 0.4 + 5;
			}
			else{
				int rotate = lastGateLocation.horizontalAngle  * 0.4 + 5;
			}
			//Turn robot to gate
			if (lastGateLocation.horizontalDev > -30 && lastGateLocation.horizontalDev < 30){
				coilgun->ToggleTribbler(false);
				wheels->Stop();
				std::chrono::milliseconds dura(50);
				std::this_thread::sleep_for(dura);
				coilgun->Kick();
				return LOCATE_BALL;
			}
			else if (lastGateLocation.horizontalDev < -30){
				wheels->Rotate(0, 10);
			}
			else{
				wheels->Rotate(1, 10);
			}
		}

	}

}

DriveMode AutoPilot::RecoverCrash()
{
	while (wheels->IsStalled()) {
		//Backwards
		wheels->Drive(50, 180);
		std::chrono::milliseconds dura(1000);
		std::this_thread::sleep_for(dura);
		wheels->Stop();
		//Turn a littlebit
		wheels->Rotate(1, 20);
		std::this_thread::sleep_for(dura);
		wheels->Stop();
	}
	return LOCATE_BALL;
}

void AutoPilot::Run()
{

	while (!stop_thread){
		WriteInfoOnScreen();
		switch (driveMode){
		case IDLE:
			std::this_thread::sleep_for(std::chrono::milliseconds(100));
			break;
		case LOCATE_BALL:
			driveMode = LocateBall();
			break;
		case DRIVE_TO_BALL:
			driveMode = DriveToBall();
			break;
		case CATCH_BALL:
			driveMode = CatchBall();
		case LOCATE_GATE:
			driveMode = LocateGate();
			break;
		case RECOVER_CRASH:
			driveMode = RecoverCrash();
			break;
		case EXIT:
			stop_thread = true;
		}
		std::chrono::milliseconds dura(8);
		std::this_thread::sleep_for(dura);
	}
}

void AutoPilot::WriteInfoOnScreen(){
	cv::Mat infoWindow(140, 250, CV_8UC3, cv::Scalar::all(0));
	std::ostringstream oss;
	oss << "State :" << DRIVEMODE_LABELS[driveMode];
	cv::putText(infoWindow, oss.str(), cv::Point(20, 20), cv::FONT_HERSHEY_DUPLEX, 0.5, cv::Scalar(255, 255, 255));
	oss.str("");
	oss << "Ball visible :" << (ballInSight ? "yes" : "no");
	cv::putText(infoWindow, oss.str(), cv::Point(20, 50), cv::FONT_HERSHEY_DUPLEX, 0.5, cv::Scalar(255, 255, 255));
	oss.str("");
	oss << "Gate Visible :" << (gateInSight ? "yes" : "no");
	cv::putText(infoWindow, oss.str(), cv::Point(20, 80), cv::FONT_HERSHEY_DUPLEX, 0.5, cv::Scalar(255, 255, 255));
	oss.str("");
	oss << "Ball in tribbler :" << (ballInTribbler ? "yes" : "no");
	cv::putText(infoWindow, oss.str(), cv::Point(20, 110), cv::FONT_HERSHEY_DUPLEX, 0.5, cv::Scalar(255, 255, 255));
	cv::imshow("AutoPilot", infoWindow);
	cv::waitKey(1);
	return;
}

AutoPilot::~AutoPilot()
{
	coilgun->ToggleTribbler(false);
	stop_thread = true;
	threads.join_all();

}
<|endoftext|>


<commit_before>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the general parts of a Target machine.
//
//===----------------------------------------------------------------------===//

#include "llvm/Type.h"
#include "llvm/CodeGen/IntrinsicLowering.h"
#include "llvm/Target/TargetMachine.h"
#include "Support/CommandLine.h"
using namespace llvm;

//---------------------------------------------------------------------------
// Command-line options that tend to be useful on more than one back-end.
//

namespace llvm {
  bool PrintMachineCode;
  bool NoFramePointerElim;
};

namespace {
  cl::opt<bool, true> PrintCode("print-machineinstrs",
    cl::desc("Print generated machine code"),
    cl::location(PrintMachineCode), cl::init(false));

  cl::opt<bool, true>
    DisableFPElim("disable-fp-elim",
                  cl::desc("Disable frame pointer elimination optimization"),
                  cl::location(NoFramePointerElim),
                  cl::init(false));
};

//---------------------------------------------------------------------------
// TargetMachine Class
//
TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             bool LittleEndian,
                             unsigned char PtrSize, unsigned char PtrAl,
                             unsigned char DoubleAl, unsigned char FloatAl,
                             unsigned char LongAl, unsigned char IntAl,
                             unsigned char ShortAl, unsigned char ByteAl)
  : Name(name), DataLayout(name, LittleEndian,
                           PtrSize, PtrAl, DoubleAl, FloatAl, LongAl,
                           IntAl, ShortAl, ByteAl) {
  IL = il ? il : new DefaultIntrinsicLowering();
}
TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             const Module &M)
  : Name(name), DataLayout(name, &M) {
  IL = il ? il : new DefaultIntrinsicLowering();
}

TargetMachine::~TargetMachine() {
  delete IL;
}

<commit_msg>Move implemented interface header up to the top.<commit_after>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the general parts of a Target machine.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/TargetMachine.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/IntrinsicLowering.h"
#include "Support/CommandLine.h"
using namespace llvm;

//---------------------------------------------------------------------------
// Command-line options that tend to be useful on more than one back-end.
//

namespace llvm {
  bool PrintMachineCode;
  bool NoFramePointerElim;
};

namespace {
  cl::opt<bool, true> PrintCode("print-machineinstrs",
    cl::desc("Print generated machine code"),
    cl::location(PrintMachineCode), cl::init(false));

  cl::opt<bool, true>
    DisableFPElim("disable-fp-elim",
                  cl::desc("Disable frame pointer elimination optimization"),
                  cl::location(NoFramePointerElim),
                  cl::init(false));
};

//---------------------------------------------------------------------------
// TargetMachine Class
//
TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             bool LittleEndian,
                             unsigned char PtrSize, unsigned char PtrAl,
                             unsigned char DoubleAl, unsigned char FloatAl,
                             unsigned char LongAl, unsigned char IntAl,
                             unsigned char ShortAl, unsigned char ByteAl)
  : Name(name), DataLayout(name, LittleEndian,
                           PtrSize, PtrAl, DoubleAl, FloatAl, LongAl,
                           IntAl, ShortAl, ByteAl) {
  IL = il ? il : new DefaultIntrinsicLowering();
}
TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             const Module &M)
  : Name(name), DataLayout(name, &M) {
  IL = il ? il : new DefaultIntrinsicLowering();
}

TargetMachine::~TargetMachine() {
  delete IL;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: link.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 22:14:03 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_tools.hxx"

#ifndef _LINK_HXX
#include <tools/link.hxx>
#endif

/*************************************************************************
|*
|*    Link::operator==()
|*
|*    Beschreibung      LINK.SDW
|*    Ersterstellung    AM 14.02.91
|*    Letzte Aenderung  TH 07.11.95
|*
*************************************************************************/

BOOL Link::operator==( const Link& rLink ) const
{
    if ( pFunc == rLink.pFunc )
    {
        if ( pFunc )
        {
            if ( pInst == rLink.pInst )
                return TRUE;
            else
                return FALSE;
        }
        else
            return TRUE;
    }
    else
        return FALSE;
}
<commit_msg>INTEGRATION: CWS changefileheader (1.4.84); FILE MERGED 2008/04/01 12:57:26 thb 1.4.84.2: #i85898# Stripping all external header guards 2008/03/28 15:41:20 rt 1.4.84.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: link.cxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_tools.hxx"
#include <tools/link.hxx>

/*************************************************************************
|*
|*    Link::operator==()
|*
|*    Beschreibung      LINK.SDW
|*    Ersterstellung    AM 14.02.91
|*    Letzte Aenderung  TH 07.11.95
|*
*************************************************************************/

BOOL Link::operator==( const Link& rLink ) const
{
    if ( pFunc == rLink.pFunc )
    {
        if ( pFunc )
        {
            if ( pInst == rLink.pInst )
                return TRUE;
            else
                return FALSE;
        }
        else
            return TRUE;
    }
    else
        return FALSE;
}
<|endoftext|>


<commit_before>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the general parts of a Target machine.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/TargetMachine.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/IntrinsicLowering.h"
#include "Support/CommandLine.h"
using namespace llvm;

//---------------------------------------------------------------------------
// Command-line options that tend to be useful on more than one back-end.
//

namespace llvm {
  bool PrintMachineCode;
  bool NoFramePointerElim;
};

namespace {
  cl::opt<bool, true> PrintCode("print-machineinstrs",
    cl::desc("Print generated machine code"),
    cl::location(PrintMachineCode), cl::init(false));

  cl::opt<bool, true>
    DisableFPElim("disable-fp-elim",
                  cl::desc("Disable frame pointer elimination optimization"),
                  cl::location(NoFramePointerElim),
                  cl::init(false));
};

//---------------------------------------------------------------------------
// TargetMachine Class
//
TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             bool LittleEndian,
                             unsigned char PtrSize, unsigned char PtrAl,
                             unsigned char DoubleAl, unsigned char FloatAl,
                             unsigned char LongAl, unsigned char IntAl,
                             unsigned char ShortAl, unsigned char ByteAl)
  : Name(name), DataLayout(name, LittleEndian,
                           PtrSize, PtrAl, DoubleAl, FloatAl, LongAl,
                           IntAl, ShortAl, ByteAl) {
  IL = il ? il : new DefaultIntrinsicLowering();
}
TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             const Module &M)
  : Name(name), DataLayout(name, &M) {
  IL = il ? il : new DefaultIntrinsicLowering();
}

TargetMachine::~TargetMachine() {
  delete IL;
}

<commit_msg>Specify variables' namespace directly instead of using an enclosing namespace.<commit_after>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the general parts of a Target machine.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/TargetMachine.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/IntrinsicLowering.h"
#include "Support/CommandLine.h"
using namespace llvm;

//---------------------------------------------------------------------------
// Command-line options that tend to be useful on more than one back-end.
//

bool llvm::PrintMachineCode;
bool llvm::NoFramePointerElim;

namespace {
  cl::opt<bool, true> PrintCode("print-machineinstrs",
    cl::desc("Print generated machine code"),
    cl::location(PrintMachineCode), cl::init(false));

  cl::opt<bool, true>
    DisableFPElim("disable-fp-elim",
                  cl::desc("Disable frame pointer elimination optimization"),
                  cl::location(NoFramePointerElim),
                  cl::init(false));
};

//---------------------------------------------------------------------------
// TargetMachine Class
//
TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             bool LittleEndian,
                             unsigned char PtrSize, unsigned char PtrAl,
                             unsigned char DoubleAl, unsigned char FloatAl,
                             unsigned char LongAl, unsigned char IntAl,
                             unsigned char ShortAl, unsigned char ByteAl)
  : Name(name), DataLayout(name, LittleEndian,
                           PtrSize, PtrAl, DoubleAl, FloatAl, LongAl,
                           IntAl, ShortAl, ByteAl) {
  IL = il ? il : new DefaultIntrinsicLowering();
}
TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             const Module &M)
  : Name(name), DataLayout(name, &M) {
  IL = il ? il : new DefaultIntrinsicLowering();
}

TargetMachine::~TargetMachine() {
  delete IL;
}

<|endoftext|>


<commit_before>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the general parts of a Target machine.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;

//---------------------------------------------------------------------------
// Command-line options that tend to be useful on more than one back-end.
//

namespace llvm {
  bool StrongPHIElim;
  bool HasDivModLibcall;
  bool AsmVerbosityDefault(false);
}

static cl::opt<bool>
DataSections("fdata-sections",
  cl::desc("Emit data into separate sections"),
  cl::init(false));
static cl::opt<bool>
FunctionSections("ffunction-sections",
  cl::desc("Emit functions into separate sections"),
  cl::init(false));

//---------------------------------------------------------------------------
// TargetMachine Class
//

TargetMachine::TargetMachine(const Target &T,
                             StringRef TT, StringRef CPU, StringRef FS,
                             const TargetOptions &Options)
  : TheTarget(T), TargetTriple(TT), TargetCPU(CPU), TargetFS(FS),
    CodeGenInfo(0), AsmInfo(0),
    MCRelaxAll(false),
    MCNoExecStack(false),
    MCSaveTempLabels(false),
    MCUseLoc(true),
    MCUseCFI(true),
    MCUseDwarfDirectory(false),
    Options(Options) {
}

TargetMachine::~TargetMachine() {
  delete CodeGenInfo;
  delete AsmInfo;
}

/// getRelocationModel - Returns the code generation relocation model. The
/// choices are static, PIC, and dynamic-no-pic, and target default.
Reloc::Model TargetMachine::getRelocationModel() const {
  if (!CodeGenInfo)
    return Reloc::Default;
  return CodeGenInfo->getRelocationModel();
}

/// getCodeModel - Returns the code model. The choices are small, kernel,
/// medium, large, and target default.
CodeModel::Model TargetMachine::getCodeModel() const {
  if (!CodeGenInfo)
    return CodeModel::Default;
  return CodeGenInfo->getCodeModel();
}

/// getOptLevel - Returns the optimization level: None, Less,
/// Default, or Aggressive.
CodeGenOpt::Level TargetMachine::getOptLevel() const {
  if (!CodeGenInfo)
    return CodeGenOpt::Default;
  return CodeGenInfo->getOptLevel();
}

bool TargetMachine::getAsmVerbosityDefault() {
  return AsmVerbosityDefault;
}

void TargetMachine::setAsmVerbosityDefault(bool V) {
  AsmVerbosityDefault = V;
}

bool TargetMachine::getFunctionSections() {
  return FunctionSections;
}

bool TargetMachine::getDataSections() {
  return DataSections;
}

void TargetMachine::setFunctionSections(bool V) {
  FunctionSections = V;
}

void TargetMachine::setDataSections(bool V) {
  DataSections = V;
}

<commit_msg>Also remove unnecessary includes from this file, which was supposed to be part of r146334!<commit_after>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the general parts of a Target machine.
//
//===----------------------------------------------------------------------===//

#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;

//---------------------------------------------------------------------------
// Command-line options that tend to be useful on more than one back-end.
//

namespace llvm {
  bool StrongPHIElim;
  bool HasDivModLibcall;
  bool AsmVerbosityDefault(false);
}

static cl::opt<bool>
DataSections("fdata-sections",
  cl::desc("Emit data into separate sections"),
  cl::init(false));
static cl::opt<bool>
FunctionSections("ffunction-sections",
  cl::desc("Emit functions into separate sections"),
  cl::init(false));

//---------------------------------------------------------------------------
// TargetMachine Class
//

TargetMachine::TargetMachine(const Target &T,
                             StringRef TT, StringRef CPU, StringRef FS,
                             const TargetOptions &Options)
  : TheTarget(T), TargetTriple(TT), TargetCPU(CPU), TargetFS(FS),
    CodeGenInfo(0), AsmInfo(0),
    MCRelaxAll(false),
    MCNoExecStack(false),
    MCSaveTempLabels(false),
    MCUseLoc(true),
    MCUseCFI(true),
    MCUseDwarfDirectory(false),
    Options(Options) {
}

TargetMachine::~TargetMachine() {
  delete CodeGenInfo;
  delete AsmInfo;
}

/// getRelocationModel - Returns the code generation relocation model. The
/// choices are static, PIC, and dynamic-no-pic, and target default.
Reloc::Model TargetMachine::getRelocationModel() const {
  if (!CodeGenInfo)
    return Reloc::Default;
  return CodeGenInfo->getRelocationModel();
}

/// getCodeModel - Returns the code model. The choices are small, kernel,
/// medium, large, and target default.
CodeModel::Model TargetMachine::getCodeModel() const {
  if (!CodeGenInfo)
    return CodeModel::Default;
  return CodeGenInfo->getCodeModel();
}

/// getOptLevel - Returns the optimization level: None, Less,
/// Default, or Aggressive.
CodeGenOpt::Level TargetMachine::getOptLevel() const {
  if (!CodeGenInfo)
    return CodeGenOpt::Default;
  return CodeGenInfo->getOptLevel();
}

bool TargetMachine::getAsmVerbosityDefault() {
  return AsmVerbosityDefault;
}

void TargetMachine::setAsmVerbosityDefault(bool V) {
  AsmVerbosityDefault = V;
}

bool TargetMachine::getFunctionSections() {
  return FunctionSections;
}

bool TargetMachine::getDataSections() {
  return DataSections;
}

void TargetMachine::setFunctionSections(bool V) {
  FunctionSections = V;
}

void TargetMachine::setDataSections(bool V) {
  DataSections = V;
}

<|endoftext|>