зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 1 changesets (bug 1309172) for breakpad related failures. CLOSED TREE
Backed out changeset 07a62b4e7923 (bug 1309172)
This commit is contained in:
Родитель
69b0fa243f
Коммит
2da518e733
|
@ -255,7 +255,7 @@ CrashGenerationServer::ClientEvent(short revents)
|
|||
}
|
||||
|
||||
if (crashing_pid == -1 || signal_fd == -1) {
|
||||
if (signal_fd != -1)
|
||||
if (signal_fd)
|
||||
close(signal_fd);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -41,21 +41,8 @@ namespace google_breakpad {
|
|||
// One of these is produced for each mapping in the process (i.e. line in
|
||||
// /proc/$x/maps).
|
||||
struct MappingInfo {
|
||||
// On Android, relocation packing can mean that the reported start
|
||||
// address of the mapping must be adjusted by a bias in order to
|
||||
// compensate for the compression of the relocation section. The
|
||||
// following two members hold (after LateInit) the adjusted mapping
|
||||
// range. See crbug.com/606972 for more information.
|
||||
uintptr_t start_addr;
|
||||
size_t size;
|
||||
// When Android relocation packing causes |start_addr| and |size| to
|
||||
// be modified with a load bias, we need to remember the unbiased
|
||||
// address range. The following structure holds the original mapping
|
||||
// address range as reported by the operating system.
|
||||
struct {
|
||||
uintptr_t start_addr;
|
||||
uintptr_t end_addr;
|
||||
} system_mapping_info;
|
||||
size_t offset; // offset into the backed file.
|
||||
bool exec; // true if the mapping has the execute bit set.
|
||||
char name[NAME_MAX];
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace google_breakpad {
|
|||
|
||||
// Minidump defines register structures which are different from the raw
|
||||
// structures which we get from the kernel. These are platform specific
|
||||
// functions to juggle the ucontext_t and user structures into minidump format.
|
||||
// functions to juggle the ucontext and user structures into minidump format.
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Wraps platform-dependent implementations of accessors to ucontext_t structs.
|
||||
// Wraps platform-dependent implementations of accessors to ucontext structs.
|
||||
struct UContextReader {
|
||||
static uintptr_t GetStackPointer(const ucontext_t* uc);
|
||||
|
||||
|
|
|
@ -105,6 +105,12 @@
|
|||
#define PR_SET_PTRACER 0x59616d61
|
||||
#endif
|
||||
|
||||
// A wrapper for the tgkill syscall: send a signal to a specific thread.
|
||||
static int _tgkill(pid_t tgid, pid_t tid, int sig) {
|
||||
return syscall(__NR_tgkill, tgid, tid, sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
namespace {
|
||||
|
@ -212,7 +218,6 @@ pthread_mutex_t g_handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER;
|
|||
// time can use |g_crash_context_|.
|
||||
ExceptionHandler::CrashContext g_crash_context_;
|
||||
|
||||
FirstChanceHandler g_first_chance_handler_ = nullptr;
|
||||
} // namespace
|
||||
|
||||
// Runs before crashing: normal context.
|
||||
|
@ -326,18 +331,6 @@ void ExceptionHandler::RestoreHandlersLocked() {
|
|||
// Runs on the crashing thread.
|
||||
// static
|
||||
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
|
||||
|
||||
// Give the first chance handler a chance to recover from this signal
|
||||
//
|
||||
// This is primarily used by V8. V8 uses guard regions to guarantee memory
|
||||
// safety in WebAssembly. This means some signals might be expected if they
|
||||
// originate from Wasm code while accessing the guard region. We give V8 the
|
||||
// chance to handle and recover from these signals first.
|
||||
if (g_first_chance_handler_ != nullptr &&
|
||||
g_first_chance_handler_(sig, info, uc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// All the exception signals are blocked at this point.
|
||||
pthread_mutex_lock(&g_handler_stack_mutex_);
|
||||
|
||||
|
@ -353,7 +346,6 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
|
|||
// will call the function with the right arguments.
|
||||
struct sigaction cur_handler;
|
||||
if (sigaction(sig, NULL, &cur_handler) == 0 &&
|
||||
cur_handler.sa_sigaction == SignalHandler &&
|
||||
(cur_handler.sa_flags & SA_SIGINFO) == 0) {
|
||||
// Reset signal handler with the right flags.
|
||||
sigemptyset(&cur_handler.sa_mask);
|
||||
|
@ -395,7 +387,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
|
|||
// In order to retrigger it, we have to queue a new signal by calling
|
||||
// kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is
|
||||
// due to the kernel sending a SIGABRT from a user request via SysRQ.
|
||||
if (sys_tgkill(getpid(), syscall(__NR_gettid), sig) < 0) {
|
||||
if (_tgkill(getpid(), syscall(__NR_gettid), sig) < 0) {
|
||||
// If we failed to kill ourselves (e.g. because a sandbox disallows us
|
||||
// to do so), we instead resort to terminating our process. This will
|
||||
// result in an incorrect exit code.
|
||||
|
@ -422,14 +414,9 @@ struct ThreadArgument {
|
|||
int ExceptionHandler::ThreadEntry(void *arg) {
|
||||
const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
|
||||
|
||||
// Close the write end of the pipe. This allows us to fail if the parent dies
|
||||
// while waiting for the continue signal.
|
||||
sys_close(thread_arg->handler->fdes[1]);
|
||||
|
||||
// Block here until the crashing process unblocks us when
|
||||
// we're allowed to use ptrace
|
||||
thread_arg->handler->WaitForContinueSignal();
|
||||
sys_close(thread_arg->handler->fdes[0]);
|
||||
|
||||
return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context,
|
||||
thread_arg->context_size) == false;
|
||||
|
@ -437,7 +424,7 @@ int ExceptionHandler::ThreadEntry(void *arg) {
|
|||
|
||||
// This function runs in a compromised context: see the top of the file.
|
||||
// Runs on the crashing thread.
|
||||
bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) {
|
||||
bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
|
||||
if (filter_ && !filter_(callback_context_))
|
||||
return false;
|
||||
|
||||
|
@ -536,8 +523,8 @@ bool ExceptionHandler::GenerateDump(CrashContext *context) {
|
|||
}
|
||||
|
||||
const pid_t child = sys_clone(
|
||||
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
|
||||
NULL);
|
||||
ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
|
||||
&thread_arg, NULL, NULL, NULL);
|
||||
if (child == -1) {
|
||||
sys_close(fdes[0]);
|
||||
sys_close(fdes[1]);
|
||||
|
@ -561,14 +548,13 @@ bool ExceptionHandler::GenerateDump(CrashContext *context) {
|
|||
logger::write(childMsg, my_strlen(childMsg));
|
||||
}
|
||||
|
||||
// Close the read end of the pipe.
|
||||
sys_close(fdes[0]);
|
||||
// Allow the child to ptrace us
|
||||
sys_prctl(PR_SET_PTRACER, child, 0, 0, 0);
|
||||
SendContinueSignalToChild();
|
||||
int status = 0;
|
||||
int status;
|
||||
const int r = HANDLE_EINTR(sys_waitpid(child, &status, __WALL));
|
||||
|
||||
sys_close(fdes[0]);
|
||||
sys_close(fdes[1]);
|
||||
|
||||
if (r == -1) {
|
||||
|
@ -624,20 +610,12 @@ void ExceptionHandler::WaitForContinueSignal() {
|
|||
// Runs on the cloned process.
|
||||
bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
|
||||
size_t context_size) {
|
||||
const bool may_skip_dump =
|
||||
minidump_descriptor_.skip_dump_if_principal_mapping_not_referenced();
|
||||
const uintptr_t principal_mapping_address =
|
||||
minidump_descriptor_.address_within_principal_mapping();
|
||||
const bool sanitize_stacks = minidump_descriptor_.sanitize_stacks();
|
||||
if (minidump_descriptor_.IsMicrodumpOnConsole()) {
|
||||
return google_breakpad::WriteMicrodump(
|
||||
crashing_process,
|
||||
context,
|
||||
context_size,
|
||||
mapping_list_,
|
||||
may_skip_dump,
|
||||
principal_mapping_address,
|
||||
sanitize_stacks,
|
||||
*minidump_descriptor_.microdump_extra_info());
|
||||
}
|
||||
if (minidump_descriptor_.IsFD()) {
|
||||
|
@ -647,10 +625,7 @@ bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
|
|||
context,
|
||||
context_size,
|
||||
mapping_list_,
|
||||
app_memory_list_,
|
||||
may_skip_dump,
|
||||
principal_mapping_address,
|
||||
sanitize_stacks);
|
||||
app_memory_list_);
|
||||
}
|
||||
return google_breakpad::WriteMinidump(minidump_descriptor_.path(),
|
||||
minidump_descriptor_.size_limit(),
|
||||
|
@ -658,10 +633,7 @@ bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
|
|||
context,
|
||||
context_size,
|
||||
mapping_list_,
|
||||
app_memory_list_,
|
||||
may_skip_dump,
|
||||
principal_mapping_address,
|
||||
sanitize_stacks);
|
||||
app_memory_list_);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -814,8 +786,4 @@ bool ExceptionHandler::WriteMinidumpForChild(pid_t child,
|
|||
return callback ? callback(descriptor, callback_context, true) : true;
|
||||
}
|
||||
|
||||
void SetFirstChanceExceptionHandler(FirstChanceHandler callback) {
|
||||
g_first_chance_handler_ = callback;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -194,8 +194,8 @@ class ExceptionHandler {
|
|||
ucontext_t context;
|
||||
#if !defined(__ARM_EABI__) && !defined(__mips__)
|
||||
// #ifdef this out because FP state is not part of user ABI for Linux ARM.
|
||||
// In case of MIPS Linux FP state is already part of ucontext_t so
|
||||
// 'float_state' is not required.
|
||||
// In case of MIPS Linux FP state is already part of struct
|
||||
// ucontext so 'float_state' is not required.
|
||||
fpstate_t float_state;
|
||||
#endif
|
||||
};
|
||||
|
@ -262,7 +262,7 @@ class ExceptionHandler {
|
|||
// can do this. We create a pipe which we can use to block the
|
||||
// cloned process after creating it, until we have explicitly enabled
|
||||
// ptrace. This is used to store the file descriptors for the pipe
|
||||
int fdes[2] = {-1, -1};
|
||||
int fdes[2];
|
||||
|
||||
// Callers can add extra info about mappings for cases where the
|
||||
// dumper code cannot extract enough information from /proc/<pid>/maps.
|
||||
|
@ -273,10 +273,6 @@ class ExceptionHandler {
|
|||
AppMemoryList app_memory_list_;
|
||||
};
|
||||
|
||||
|
||||
typedef bool (*FirstChanceHandler)(int, void*, void*);
|
||||
void SetFirstChanceExceptionHandler(FirstChanceHandler callback);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
@ -258,66 +257,6 @@ TEST(ExceptionHandlerTest, ChildCrashWithFD) {
|
|||
ASSERT_NO_FATAL_FAILURE(ChildCrash(true));
|
||||
}
|
||||
|
||||
#if !defined(__ANDROID_API__) || __ANDROID_API__ >= __ANDROID_API_N__
|
||||
static void* SleepFunction(void* unused) {
|
||||
while (true) usleep(1000000);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void* CrashFunction(void* b_ptr) {
|
||||
pthread_barrier_t* b = reinterpret_cast<pthread_barrier_t*>(b_ptr);
|
||||
pthread_barrier_wait(b);
|
||||
DoNullPointerDereference();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Tests that concurrent crashes do not enter a loop by alternately triggering
|
||||
// the signal handler.
|
||||
TEST(ExceptionHandlerTest, ParallelChildCrashesDontHang) {
|
||||
AutoTempDir temp_dir;
|
||||
const pid_t child = fork();
|
||||
if (child == 0) {
|
||||
google_breakpad::scoped_ptr<ExceptionHandler> handler(
|
||||
new ExceptionHandler(MinidumpDescriptor(temp_dir.path()), NULL, NULL,
|
||||
NULL, true, -1));
|
||||
|
||||
// We start a number of threads to make sure handling the signal takes
|
||||
// enough time for the second thread to enter the signal handler.
|
||||
int num_sleep_threads = 100;
|
||||
google_breakpad::scoped_array<pthread_t> sleep_threads(
|
||||
new pthread_t[num_sleep_threads]);
|
||||
for (int i = 0; i < num_sleep_threads; ++i) {
|
||||
ASSERT_EQ(0, pthread_create(&sleep_threads[i], NULL, SleepFunction,
|
||||
NULL));
|
||||
}
|
||||
|
||||
int num_crash_threads = 2;
|
||||
google_breakpad::scoped_array<pthread_t> crash_threads(
|
||||
new pthread_t[num_crash_threads]);
|
||||
// Barrier to synchronize crashing both threads at the same time.
|
||||
pthread_barrier_t b;
|
||||
ASSERT_EQ(0, pthread_barrier_init(&b, NULL, num_crash_threads + 1));
|
||||
for (int i = 0; i < num_crash_threads; ++i) {
|
||||
ASSERT_EQ(0, pthread_create(&crash_threads[i], NULL, CrashFunction, &b));
|
||||
}
|
||||
pthread_barrier_wait(&b);
|
||||
for (int i = 0; i < num_crash_threads; ++i) {
|
||||
ASSERT_EQ(0, pthread_join(crash_threads[i], NULL));
|
||||
}
|
||||
}
|
||||
|
||||
// Wait a while until the child should have crashed.
|
||||
usleep(1000000);
|
||||
// Kill the child if it is still running.
|
||||
kill(child, SIGKILL);
|
||||
|
||||
// If the child process terminated by itself, it will have returned SIGSEGV.
|
||||
// If however it got stuck in a loop, it will have been killed by the
|
||||
// SIGKILL.
|
||||
ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
|
||||
}
|
||||
#endif // !defined(__ANDROID_API__) || __ANDROID_API__ >= __ANDROID_API_N__
|
||||
|
||||
static bool DoneCallbackReturnFalse(const MinidumpDescriptor& descriptor,
|
||||
void* context,
|
||||
bool succeeded) {
|
||||
|
@ -526,29 +465,6 @@ TEST(ExceptionHandlerTest, StackedHandlersUnhandledToBottom) {
|
|||
ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
|
||||
}
|
||||
|
||||
namespace {
|
||||
const int kSimpleFirstChanceReturnStatus = 42;
|
||||
bool SimpleFirstChanceHandler(int, void*, void*) {
|
||||
_exit(kSimpleFirstChanceReturnStatus);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ExceptionHandlerTest, FirstChanceHandlerRuns) {
|
||||
AutoTempDir temp_dir;
|
||||
|
||||
const pid_t child = fork();
|
||||
if (child == 0) {
|
||||
ExceptionHandler handler(
|
||||
MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
|
||||
google_breakpad::SetFirstChanceExceptionHandler(SimpleFirstChanceHandler);
|
||||
DoNullPointerDereference();
|
||||
}
|
||||
int status;
|
||||
ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
|
||||
ASSERT_TRUE(WIFEXITED(status));
|
||||
ASSERT_EQ(kSimpleFirstChanceReturnStatus, WEXITSTATUS(status));
|
||||
}
|
||||
|
||||
#endif // !ADDRESS_SANITIZER
|
||||
|
||||
const unsigned char kIllegalInstruction[] = {
|
||||
|
|
|
@ -44,11 +44,6 @@ MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor)
|
|||
directory_(descriptor.directory_),
|
||||
c_path_(NULL),
|
||||
size_limit_(descriptor.size_limit_),
|
||||
address_within_principal_mapping_(
|
||||
descriptor.address_within_principal_mapping_),
|
||||
skip_dump_if_principal_mapping_not_referenced_(
|
||||
descriptor.skip_dump_if_principal_mapping_not_referenced_),
|
||||
sanitize_stacks_(descriptor.sanitize_stacks_),
|
||||
microdump_extra_info_(descriptor.microdump_extra_info_) {
|
||||
// The copy constructor is not allowed to be called on a MinidumpDescriptor
|
||||
// with a valid path_, as getting its c_path_ would require the heap which
|
||||
|
@ -70,11 +65,6 @@ MinidumpDescriptor& MinidumpDescriptor::operator=(
|
|||
UpdatePath();
|
||||
}
|
||||
size_limit_ = descriptor.size_limit_;
|
||||
address_within_principal_mapping_ =
|
||||
descriptor.address_within_principal_mapping_;
|
||||
skip_dump_if_principal_mapping_not_referenced_ =
|
||||
descriptor.skip_dump_if_principal_mapping_not_referenced_;
|
||||
sanitize_stacks_ = descriptor.sanitize_stacks_;
|
||||
microdump_extra_info_ = descriptor.microdump_extra_info_;
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -53,19 +53,14 @@ class MinidumpDescriptor {
|
|||
MinidumpDescriptor()
|
||||
: mode_(kUninitialized),
|
||||
fd_(-1),
|
||||
size_limit_(-1),
|
||||
address_within_principal_mapping_(0),
|
||||
skip_dump_if_principal_mapping_not_referenced_(false) {}
|
||||
size_limit_(-1) {}
|
||||
|
||||
explicit MinidumpDescriptor(const string& directory)
|
||||
: mode_(kWriteMinidumpToFile),
|
||||
fd_(-1),
|
||||
directory_(directory),
|
||||
c_path_(NULL),
|
||||
size_limit_(-1),
|
||||
address_within_principal_mapping_(0),
|
||||
skip_dump_if_principal_mapping_not_referenced_(false),
|
||||
sanitize_stacks_(false) {
|
||||
size_limit_(-1) {
|
||||
assert(!directory.empty());
|
||||
}
|
||||
|
||||
|
@ -73,20 +68,14 @@ class MinidumpDescriptor {
|
|||
: mode_(kWriteMinidumpToFd),
|
||||
fd_(fd),
|
||||
c_path_(NULL),
|
||||
size_limit_(-1),
|
||||
address_within_principal_mapping_(0),
|
||||
skip_dump_if_principal_mapping_not_referenced_(false),
|
||||
sanitize_stacks_(false) {
|
||||
size_limit_(-1) {
|
||||
assert(fd != -1);
|
||||
}
|
||||
|
||||
explicit MinidumpDescriptor(const MicrodumpOnConsole&)
|
||||
: mode_(kWriteMicrodumpToConsole),
|
||||
fd_(-1),
|
||||
size_limit_(-1),
|
||||
address_within_principal_mapping_(0),
|
||||
skip_dump_if_principal_mapping_not_referenced_(false),
|
||||
sanitize_stacks_(false) {}
|
||||
size_limit_(-1) {}
|
||||
|
||||
explicit MinidumpDescriptor(const MinidumpDescriptor& descriptor);
|
||||
MinidumpDescriptor& operator=(const MinidumpDescriptor& descriptor);
|
||||
|
@ -112,28 +101,6 @@ class MinidumpDescriptor {
|
|||
off_t size_limit() const { return size_limit_; }
|
||||
void set_size_limit(off_t limit) { size_limit_ = limit; }
|
||||
|
||||
uintptr_t address_within_principal_mapping() const {
|
||||
return address_within_principal_mapping_;
|
||||
}
|
||||
void set_address_within_principal_mapping(
|
||||
uintptr_t address_within_principal_mapping) {
|
||||
address_within_principal_mapping_ = address_within_principal_mapping;
|
||||
}
|
||||
|
||||
bool skip_dump_if_principal_mapping_not_referenced() {
|
||||
return skip_dump_if_principal_mapping_not_referenced_;
|
||||
}
|
||||
void set_skip_dump_if_principal_mapping_not_referenced(
|
||||
bool skip_dump_if_principal_mapping_not_referenced) {
|
||||
skip_dump_if_principal_mapping_not_referenced_ =
|
||||
skip_dump_if_principal_mapping_not_referenced;
|
||||
}
|
||||
|
||||
bool sanitize_stacks() const { return sanitize_stacks_; }
|
||||
void set_sanitize_stacks(bool sanitize_stacks) {
|
||||
sanitize_stacks_ = sanitize_stacks;
|
||||
}
|
||||
|
||||
MicrodumpExtraInfo* microdump_extra_info() {
|
||||
assert(IsMicrodumpOnConsole());
|
||||
return µdump_extra_info_;
|
||||
|
@ -165,23 +132,6 @@ class MinidumpDescriptor {
|
|||
|
||||
off_t size_limit_;
|
||||
|
||||
// This member points somewhere into the main module for this
|
||||
// process (the module that is considerered interesting for the
|
||||
// purposes of debugging crashes).
|
||||
uintptr_t address_within_principal_mapping_;
|
||||
|
||||
// If set, threads that do not reference the address range
|
||||
// associated with |address_within_principal_mapping_| will not have their
|
||||
// stacks logged.
|
||||
bool skip_dump_if_principal_mapping_not_referenced_;
|
||||
|
||||
// If set, stacks are sanitized to remove PII. This involves
|
||||
// overwriting any pointer-aligned words that are not either
|
||||
// pointers into a process mapping or small integers (+/-4096). This
|
||||
// leaves enough information to unwind stacks, and preserve some
|
||||
// register values, but elides strings and other program data.
|
||||
bool sanitize_stacks_;
|
||||
|
||||
// The extra microdump data (e.g. product name/version, build
|
||||
// fingerprint, gpu fingerprint) that should be appended to the dump
|
||||
// (microdump only). Microdumps don't have the ability of appending
|
||||
|
|
|
@ -132,9 +132,6 @@ class MicrodumpWriter {
|
|||
public:
|
||||
MicrodumpWriter(const ExceptionHandler::CrashContext* context,
|
||||
const MappingList& mappings,
|
||||
bool skip_dump_if_principal_mapping_not_referenced,
|
||||
uintptr_t address_within_principal_mapping,
|
||||
bool sanitize_stack,
|
||||
const MicrodumpExtraInfo& microdump_extra_info,
|
||||
LinuxDumper* dumper)
|
||||
: ucontext_(context ? &context->context : NULL),
|
||||
|
@ -143,16 +140,8 @@ class MicrodumpWriter {
|
|||
#endif
|
||||
dumper_(dumper),
|
||||
mapping_list_(mappings),
|
||||
skip_dump_if_principal_mapping_not_referenced_(
|
||||
skip_dump_if_principal_mapping_not_referenced),
|
||||
address_within_principal_mapping_(address_within_principal_mapping),
|
||||
sanitize_stack_(sanitize_stack),
|
||||
microdump_extra_info_(microdump_extra_info),
|
||||
log_line_(NULL),
|
||||
stack_copy_(NULL),
|
||||
stack_len_(0),
|
||||
stack_lower_bound_(0),
|
||||
stack_pointer_(0) {
|
||||
log_line_(NULL) {
|
||||
log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize));
|
||||
if (log_line_)
|
||||
log_line_[0] = '\0'; // Clear out the log line buffer.
|
||||
|
@ -170,32 +159,25 @@ class MicrodumpWriter {
|
|||
return dumper_->ThreadsSuspend() && dumper_->LateInit();
|
||||
}
|
||||
|
||||
void Dump() {
|
||||
CaptureResult stack_capture_result = CaptureCrashingThreadStack(-1);
|
||||
if (stack_capture_result == CAPTURE_UNINTERESTING) {
|
||||
LogLine("Microdump skipped (uninteresting)");
|
||||
return;
|
||||
}
|
||||
|
||||
bool Dump() {
|
||||
bool success;
|
||||
LogLine("-----BEGIN BREAKPAD MICRODUMP-----");
|
||||
DumpProductInformation();
|
||||
DumpOSInformation();
|
||||
DumpProcessType();
|
||||
DumpCrashReason();
|
||||
DumpGPUInformation();
|
||||
#if !defined(__LP64__)
|
||||
DumpFreeSpace();
|
||||
#endif
|
||||
if (stack_capture_result == CAPTURE_OK)
|
||||
DumpThreadStack();
|
||||
DumpCPUState();
|
||||
DumpMappings();
|
||||
success = DumpCrashingThread();
|
||||
if (success)
|
||||
success = DumpMappings();
|
||||
LogLine("-----END BREAKPAD MICRODUMP-----");
|
||||
dumper_->ThreadsResume();
|
||||
return success;
|
||||
}
|
||||
|
||||
private:
|
||||
enum CaptureResult { CAPTURE_OK, CAPTURE_FAILED, CAPTURE_UNINTERESTING };
|
||||
|
||||
// Writes one line to the system log.
|
||||
void LogLine(const char* msg) {
|
||||
#if defined(__ANDROID__)
|
||||
|
@ -239,44 +221,7 @@ class MicrodumpWriter {
|
|||
// Writes out the current line buffer on the system log.
|
||||
void LogCommitLine() {
|
||||
LogLine(log_line_);
|
||||
log_line_[0] = 0;
|
||||
}
|
||||
|
||||
CaptureResult CaptureCrashingThreadStack(int max_stack_len) {
|
||||
stack_pointer_ = UContextReader::GetStackPointer(ucontext_);
|
||||
|
||||
if (!dumper_->GetStackInfo(reinterpret_cast<const void**>(&stack_lower_bound_),
|
||||
&stack_len_, stack_pointer_)) {
|
||||
return CAPTURE_FAILED;
|
||||
}
|
||||
|
||||
if (max_stack_len >= 0 &&
|
||||
stack_len_ > static_cast<size_t>(max_stack_len)) {
|
||||
stack_len_ = max_stack_len;
|
||||
}
|
||||
|
||||
stack_copy_ = reinterpret_cast<uint8_t*>(Alloc(stack_len_));
|
||||
dumper_->CopyFromProcess(stack_copy_, dumper_->crash_thread(),
|
||||
reinterpret_cast<const void*>(stack_lower_bound_),
|
||||
stack_len_);
|
||||
|
||||
if (!skip_dump_if_principal_mapping_not_referenced_) return CAPTURE_OK;
|
||||
|
||||
const MappingInfo* principal_mapping =
|
||||
dumper_->FindMappingNoBias(address_within_principal_mapping_);
|
||||
if (!principal_mapping) return CAPTURE_UNINTERESTING;
|
||||
|
||||
uintptr_t low_addr = principal_mapping->system_mapping_info.start_addr;
|
||||
uintptr_t high_addr = principal_mapping->system_mapping_info.end_addr;
|
||||
uintptr_t pc = UContextReader::GetInstructionPointer(ucontext_);
|
||||
if (low_addr <= pc && pc <= high_addr) return CAPTURE_OK;
|
||||
|
||||
if (dumper_->StackHasPointerToMapping(stack_copy_, stack_len_,
|
||||
stack_pointer_ - stack_lower_bound_,
|
||||
*principal_mapping)) {
|
||||
return CAPTURE_OK;
|
||||
}
|
||||
return CAPTURE_UNINTERESTING;
|
||||
my_strlcpy(log_line_, "", kLineBufferSize);
|
||||
}
|
||||
|
||||
void DumpProductInformation() {
|
||||
|
@ -299,16 +244,6 @@ class MicrodumpWriter {
|
|||
LogCommitLine();
|
||||
}
|
||||
|
||||
void DumpCrashReason() {
|
||||
LogAppend("R ");
|
||||
LogAppend(dumper_->crash_signal());
|
||||
LogAppend(" ");
|
||||
LogAppend(dumper_->GetCrashSignalString());
|
||||
LogAppend(" ");
|
||||
LogAppend(dumper_->crash_address());
|
||||
LogCommitLine();
|
||||
}
|
||||
|
||||
void DumpOSInformation() {
|
||||
const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF));
|
||||
|
||||
|
@ -380,42 +315,87 @@ class MicrodumpWriter {
|
|||
LogCommitLine();
|
||||
}
|
||||
|
||||
void DumpThreadStack() {
|
||||
if (sanitize_stack_) {
|
||||
dumper_->SanitizeStackCopy(stack_copy_, stack_len_, stack_pointer_,
|
||||
stack_pointer_ - stack_lower_bound_);
|
||||
bool DumpThreadStack(uint32_t thread_id,
|
||||
uintptr_t stack_pointer,
|
||||
int max_stack_len,
|
||||
uint8_t** stack_copy) {
|
||||
*stack_copy = NULL;
|
||||
const void* stack;
|
||||
size_t stack_len;
|
||||
|
||||
if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
|
||||
// The stack pointer might not be available. In this case we don't hard
|
||||
// fail, just produce a (almost useless) microdump w/o a stack section.
|
||||
return true;
|
||||
}
|
||||
|
||||
LogAppend("S 0 ");
|
||||
LogAppend(stack_pointer_);
|
||||
LogAppend(stack_pointer);
|
||||
LogAppend(" ");
|
||||
LogAppend(stack_lower_bound_);
|
||||
LogAppend(reinterpret_cast<uintptr_t>(stack));
|
||||
LogAppend(" ");
|
||||
LogAppend(stack_len_);
|
||||
LogAppend(stack_len);
|
||||
LogCommitLine();
|
||||
|
||||
if (max_stack_len >= 0 &&
|
||||
stack_len > static_cast<unsigned int>(max_stack_len)) {
|
||||
stack_len = max_stack_len;
|
||||
}
|
||||
|
||||
*stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
|
||||
dumper_->CopyFromProcess(*stack_copy, thread_id, stack, stack_len);
|
||||
|
||||
// Dump the content of the stack, splicing it into chunks which size is
|
||||
// compatible with the max logcat line size (see LOGGER_ENTRY_MAX_PAYLOAD).
|
||||
const size_t STACK_DUMP_CHUNK_SIZE = 384;
|
||||
for (size_t stack_off = 0; stack_off < stack_len_;
|
||||
for (size_t stack_off = 0; stack_off < stack_len;
|
||||
stack_off += STACK_DUMP_CHUNK_SIZE) {
|
||||
LogAppend("S ");
|
||||
LogAppend(stack_lower_bound_ + stack_off);
|
||||
LogAppend(reinterpret_cast<uintptr_t>(stack) + stack_off);
|
||||
LogAppend(" ");
|
||||
LogAppend(stack_copy_ + stack_off,
|
||||
std::min(STACK_DUMP_CHUNK_SIZE, stack_len_ - stack_off));
|
||||
LogAppend(*stack_copy + stack_off,
|
||||
std::min(STACK_DUMP_CHUNK_SIZE, stack_len - stack_off));
|
||||
LogCommitLine();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DumpCPUState() {
|
||||
RawContextCPU cpu;
|
||||
my_memset(&cpu, 0, sizeof(RawContextCPU));
|
||||
// Write information about the crashing thread.
|
||||
bool DumpCrashingThread() {
|
||||
const unsigned num_threads = dumper_->threads().size();
|
||||
|
||||
for (unsigned i = 0; i < num_threads; ++i) {
|
||||
MDRawThread thread;
|
||||
my_memset(&thread, 0, sizeof(thread));
|
||||
thread.thread_id = dumper_->threads()[i];
|
||||
|
||||
// Dump only the crashing thread.
|
||||
if (static_cast<pid_t>(thread.thread_id) != dumper_->crash_thread())
|
||||
continue;
|
||||
|
||||
assert(ucontext_);
|
||||
assert(!dumper_->IsPostMortem());
|
||||
|
||||
uint8_t* stack_copy;
|
||||
const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_);
|
||||
if (!DumpThreadStack(thread.thread_id, stack_ptr, -1, &stack_copy))
|
||||
return false;
|
||||
|
||||
RawContextCPU cpu;
|
||||
my_memset(&cpu, 0, sizeof(RawContextCPU));
|
||||
#if !defined(__ARM_EABI__) && !defined(__mips__)
|
||||
UContextReader::FillCPUContext(&cpu, ucontext_, float_state_);
|
||||
UContextReader::FillCPUContext(&cpu, ucontext_, float_state_);
|
||||
#else
|
||||
UContextReader::FillCPUContext(&cpu, ucontext_);
|
||||
UContextReader::FillCPUContext(&cpu, ucontext_);
|
||||
#endif
|
||||
DumpCPUState(&cpu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DumpCPUState(RawContextCPU* cpu) {
|
||||
LogAppend("C ");
|
||||
LogAppend(&cpu, sizeof(cpu));
|
||||
LogAppend(cpu, sizeof(*cpu));
|
||||
LogCommitLine();
|
||||
}
|
||||
|
||||
|
@ -494,12 +474,6 @@ class MicrodumpWriter {
|
|||
|
||||
#if !defined(__LP64__)
|
||||
void DumpFreeSpace() {
|
||||
const MappingInfo* stack_mapping = nullptr;
|
||||
ThreadInfo info;
|
||||
if (dumper_->GetThreadInfoByIndex(dumper_->GetMainThreadIndex(), &info)) {
|
||||
stack_mapping = dumper_->FindMappingNoBias(info.stack_pointer);
|
||||
}
|
||||
|
||||
const google_breakpad::wasteful_vector<MappingInfo*>& mappings =
|
||||
dumper_->mappings();
|
||||
if (mappings.size() == 0) return;
|
||||
|
@ -532,14 +506,6 @@ class MicrodumpWriter {
|
|||
++curr;
|
||||
}
|
||||
|
||||
if (mappings[curr] == stack_mapping) {
|
||||
// Because we can't determine the top of userspace mappable
|
||||
// memory we treat the start of the process stack as the top
|
||||
// of the allocatable address space. Once we reach
|
||||
// |stack_mapping| we are done scanning for free space regions.
|
||||
break;
|
||||
}
|
||||
|
||||
size_t next = NextOrderedMapping(mappings, curr);
|
||||
if (next == std::numeric_limits<size_t>::max())
|
||||
break;
|
||||
|
@ -581,7 +547,7 @@ class MicrodumpWriter {
|
|||
#endif
|
||||
|
||||
// Write information about the mappings in effect.
|
||||
void DumpMappings() {
|
||||
bool DumpMappings() {
|
||||
// First write all the mappings from the dumper
|
||||
for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
|
||||
const MappingInfo& mapping = *dumper_->mappings()[i];
|
||||
|
@ -600,6 +566,7 @@ class MicrodumpWriter {
|
|||
++iter) {
|
||||
DumpModule(iter->first, false, 0, iter->second);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); }
|
||||
|
@ -610,25 +577,8 @@ class MicrodumpWriter {
|
|||
#endif
|
||||
LinuxDumper* dumper_;
|
||||
const MappingList& mapping_list_;
|
||||
bool skip_dump_if_principal_mapping_not_referenced_;
|
||||
uintptr_t address_within_principal_mapping_;
|
||||
bool sanitize_stack_;
|
||||
const MicrodumpExtraInfo microdump_extra_info_;
|
||||
char* log_line_;
|
||||
|
||||
// The local copy of crashed process stack memory, beginning at
|
||||
// |stack_lower_bound_|.
|
||||
uint8_t* stack_copy_;
|
||||
|
||||
// The length of crashed process stack copy.
|
||||
size_t stack_len_;
|
||||
|
||||
// The address of the page containing the stack pointer in the
|
||||
// crashed process. |stack_lower_bound_| <= |stack_pointer_|
|
||||
uintptr_t stack_lower_bound_;
|
||||
|
||||
// The stack pointer of the crashed thread.
|
||||
uintptr_t stack_pointer_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@ -638,9 +588,6 @@ bool WriteMicrodump(pid_t crashing_process,
|
|||
const void* blob,
|
||||
size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
bool skip_dump_if_principal_mapping_not_referenced,
|
||||
uintptr_t address_within_principal_mapping,
|
||||
bool sanitize_stack,
|
||||
const MicrodumpExtraInfo& microdump_extra_info) {
|
||||
LinuxPtraceDumper dumper(crashing_process);
|
||||
const ExceptionHandler::CrashContext* context = NULL;
|
||||
|
@ -648,17 +595,15 @@ bool WriteMicrodump(pid_t crashing_process,
|
|||
if (blob_size != sizeof(ExceptionHandler::CrashContext))
|
||||
return false;
|
||||
context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
|
||||
dumper.SetCrashInfoFromSigInfo(context->siginfo);
|
||||
dumper.set_crash_address(
|
||||
reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
|
||||
dumper.set_crash_signal(context->siginfo.si_signo);
|
||||
dumper.set_crash_thread(context->tid);
|
||||
}
|
||||
MicrodumpWriter writer(context, mappings,
|
||||
skip_dump_if_principal_mapping_not_referenced,
|
||||
address_within_principal_mapping, sanitize_stack,
|
||||
microdump_extra_info, &dumper);
|
||||
MicrodumpWriter writer(context, mappings, microdump_extra_info, &dumper);
|
||||
if (!writer.Init())
|
||||
return false;
|
||||
writer.Dump();
|
||||
return true;
|
||||
return writer.Dump();
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -58,9 +58,6 @@ bool WriteMicrodump(pid_t crashing_process,
|
|||
const void* blob,
|
||||
size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
bool skip_dump_if_main_module_not_referenced,
|
||||
uintptr_t address_within_main_module,
|
||||
bool sanitize_stack,
|
||||
const MicrodumpExtraInfo& microdump_extra_info);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
@ -48,11 +47,6 @@
|
|||
|
||||
using namespace google_breakpad;
|
||||
|
||||
extern "C" {
|
||||
extern char __executable_start;
|
||||
extern char __etext;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
typedef testing::Test MicrodumpWriterTest;
|
||||
|
@ -65,24 +59,13 @@ MicrodumpExtraInfo MakeMicrodumpExtraInfo(
|
|||
info.build_fingerprint = build_fingerprint;
|
||||
info.product_info = product_info;
|
||||
info.gpu_fingerprint = gpu_fingerprint;
|
||||
info.process_type = "Browser";
|
||||
return info;
|
||||
}
|
||||
|
||||
bool ContainsMicrodump(const std::string& buf) {
|
||||
return std::string::npos != buf.find("-----BEGIN BREAKPAD MICRODUMP-----") &&
|
||||
std::string::npos != buf.find("-----END BREAKPAD MICRODUMP-----");
|
||||
}
|
||||
|
||||
const char kIdentifiableString[] = "_IDENTIFIABLE_";
|
||||
const uintptr_t kCrashAddress = 0xdeaddeadu;
|
||||
|
||||
void CrashAndGetMicrodump(const MappingList& mappings,
|
||||
const MicrodumpExtraInfo& microdump_extra_info,
|
||||
std::string* microdump,
|
||||
bool skip_dump_if_principal_mapping_not_referenced = false,
|
||||
uintptr_t address_within_principal_mapping = 0,
|
||||
bool sanitize_stack = false) {
|
||||
void CrashAndGetMicrodump(
|
||||
const MappingList& mappings,
|
||||
const MicrodumpExtraInfo& microdump_extra_info,
|
||||
scoped_array<char>* buf) {
|
||||
int fds[2];
|
||||
ASSERT_NE(-1, pipe(fds));
|
||||
|
||||
|
@ -91,14 +74,6 @@ void CrashAndGetMicrodump(const MappingList& mappings,
|
|||
int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
ASSERT_NE(-1, err_fd);
|
||||
|
||||
char identifiable_string[sizeof(kIdentifiableString)];
|
||||
|
||||
// This string should not appear in the resulting microdump if it
|
||||
// has been sanitized.
|
||||
strcpy(identifiable_string, kIdentifiableString);
|
||||
// Force the strcpy to not be optimized away.
|
||||
IGNORE_RET(write(STDOUT_FILENO, identifiable_string, 0));
|
||||
|
||||
const pid_t child = fork();
|
||||
if (child == 0) {
|
||||
close(fds[1]);
|
||||
|
@ -111,14 +86,9 @@ void CrashAndGetMicrodump(const MappingList& mappings,
|
|||
|
||||
ExceptionHandler::CrashContext context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
// Pretend the current context is the child context (which is
|
||||
// approximately right) so that we have a valid stack pointer, and
|
||||
// can fetch child stack data via ptrace.
|
||||
getcontext(&context.context);
|
||||
|
||||
// Set a non-zero tid to avoid tripping asserts.
|
||||
context.tid = child;
|
||||
context.siginfo.si_signo = MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED;
|
||||
context.siginfo.si_addr = reinterpret_cast<void*>(kCrashAddress);
|
||||
|
||||
// Redirect temporarily stderr to the stderr.log file.
|
||||
int save_err = dup(STDERR_FILENO);
|
||||
|
@ -126,8 +96,6 @@ void CrashAndGetMicrodump(const MappingList& mappings,
|
|||
ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO));
|
||||
|
||||
ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings,
|
||||
skip_dump_if_principal_mapping_not_referenced,
|
||||
address_within_principal_mapping, sanitize_stack,
|
||||
microdump_extra_info));
|
||||
|
||||
// Revert stderr back to the console.
|
||||
|
@ -137,38 +105,17 @@ void CrashAndGetMicrodump(const MappingList& mappings,
|
|||
// Read back the stderr file and check for the microdump marker.
|
||||
fsync(err_fd);
|
||||
lseek(err_fd, 0, SEEK_SET);
|
||||
const size_t kBufSize = 64 * 1024;
|
||||
buf->reset(new char[kBufSize]);
|
||||
ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0);
|
||||
|
||||
microdump->clear();
|
||||
char buf[1024];
|
||||
|
||||
while (true) {
|
||||
int bytes_read = IGNORE_EINTR(read(err_fd, buf, 1024));
|
||||
if (bytes_read <= 0) break;
|
||||
microdump->append(buf, buf + bytes_read);
|
||||
}
|
||||
close(err_fd);
|
||||
close(fds[1]);
|
||||
}
|
||||
|
||||
void ExtractMicrodumpStackContents(const string& microdump_content,
|
||||
string* result) {
|
||||
std::istringstream iss(microdump_content);
|
||||
result->clear();
|
||||
for (string line; std::getline(iss, line);) {
|
||||
if (line.find("S ") == 0) {
|
||||
std::istringstream stack_data(line);
|
||||
std::string key;
|
||||
std::string addr;
|
||||
std::string data;
|
||||
stack_data >> key >> addr >> data;
|
||||
EXPECT_TRUE((data.size() & 1u) == 0u);
|
||||
result->reserve(result->size() + data.size() / 2);
|
||||
for (size_t i = 0; i < data.size(); i += 2) {
|
||||
std::string byte = data.substr(i, 2);
|
||||
result->push_back(static_cast<char>(strtoul(byte.c_str(), NULL, 16)));
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----"));
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf->get(), "-----END BREAKPAD MICRODUMP-----"));
|
||||
}
|
||||
|
||||
void CheckMicrodumpContents(const string& microdump_content,
|
||||
|
@ -176,8 +123,6 @@ void CheckMicrodumpContents(const string& microdump_content,
|
|||
std::istringstream iss(microdump_content);
|
||||
bool did_find_os_info = false;
|
||||
bool did_find_product_info = false;
|
||||
bool did_find_process_type = false;
|
||||
bool did_find_crash_reason = false;
|
||||
bool did_find_gpu_info = false;
|
||||
for (string line; std::getline(iss, line);) {
|
||||
if (line.find("O ") == 0) {
|
||||
|
@ -196,28 +141,9 @@ void CheckMicrodumpContents(const string& microdump_content,
|
|||
|
||||
// Check that the build fingerprint is in the right place.
|
||||
os_info_tokens >> token;
|
||||
ASSERT_FALSE(os_info_tokens.fail());
|
||||
if (expected_info.build_fingerprint)
|
||||
ASSERT_EQ(expected_info.build_fingerprint, token);
|
||||
did_find_os_info = true;
|
||||
} else if (line.find("P ") == 0) {
|
||||
if (expected_info.process_type)
|
||||
ASSERT_EQ(string("P ") + expected_info.process_type, line);
|
||||
did_find_process_type = true;
|
||||
} else if (line.find("R ") == 0) {
|
||||
std::istringstream crash_reason_tokens(line);
|
||||
string token;
|
||||
unsigned crash_reason;
|
||||
string crash_reason_str;
|
||||
intptr_t crash_address;
|
||||
crash_reason_tokens.ignore(2); // Ignore the "R " preamble.
|
||||
crash_reason_tokens >> std::hex >> crash_reason >> crash_reason_str >>
|
||||
crash_address;
|
||||
ASSERT_FALSE(crash_reason_tokens.fail());
|
||||
ASSERT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED, crash_reason);
|
||||
ASSERT_EQ("DUMP_REQUESTED", crash_reason_str);
|
||||
ASSERT_EQ(0xDEADDEADu, kCrashAddress);
|
||||
did_find_crash_reason = true;
|
||||
} else if (line.find("V ") == 0) {
|
||||
if (expected_info.product_info)
|
||||
ASSERT_EQ(string("V ") + expected_info.product_info, line);
|
||||
|
@ -230,18 +156,9 @@ void CheckMicrodumpContents(const string& microdump_content,
|
|||
}
|
||||
ASSERT_TRUE(did_find_os_info);
|
||||
ASSERT_TRUE(did_find_product_info);
|
||||
ASSERT_TRUE(did_find_process_type);
|
||||
ASSERT_TRUE(did_find_crash_reason);
|
||||
ASSERT_TRUE(did_find_gpu_info);
|
||||
}
|
||||
|
||||
bool MicrodumpStackContains(const string& microdump_content,
|
||||
const string& expected_content) {
|
||||
string result;
|
||||
ExtractMicrodumpStackContents(microdump_content, &result);
|
||||
return result.find(kIdentifiableString) != string::npos;
|
||||
}
|
||||
|
||||
void CheckMicrodumpContents(const string& microdump_content,
|
||||
const string& expected_fingerprint,
|
||||
const string& expected_product_info,
|
||||
|
@ -274,101 +191,23 @@ TEST(MicrodumpWriterTest, BasicWithMappings) {
|
|||
memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
|
||||
mappings.push_back(mapping);
|
||||
|
||||
std::string buf;
|
||||
scoped_array<char> buf;
|
||||
CrashAndGetMicrodump(mappings, MicrodumpExtraInfo(), &buf);
|
||||
ASSERT_TRUE(ContainsMicrodump(buf));
|
||||
|
||||
#ifdef __LP64__
|
||||
ASSERT_NE(std::string::npos,
|
||||
buf.find("M 0000000000001000 000000000000002A 0000000000001000 "
|
||||
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 "
|
||||
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
|
||||
#else
|
||||
ASSERT_NE(std::string::npos,
|
||||
buf.find("M 00001000 0000002A 00001000 "
|
||||
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf.get(), "M 00001000 0000002A 00001000 "
|
||||
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
|
||||
#endif
|
||||
|
||||
// In absence of a product info in the minidump, the writer should just write
|
||||
// an unknown marker.
|
||||
ASSERT_NE(std::string::npos, buf.find("V UNKNOWN:0.0.0.0"));
|
||||
}
|
||||
|
||||
// Ensure that no output occurs if the interest region is set, but
|
||||
// doesn't overlap anything on the stack.
|
||||
TEST(MicrodumpWriterTest, NoOutputIfUninteresting) {
|
||||
const char kProductInfo[] = "MockProduct:42.0.2311.99";
|
||||
const char kBuildFingerprint[] =
|
||||
"aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys";
|
||||
const char kGPUFingerprint[] =
|
||||
"Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
|
||||
const MicrodumpExtraInfo kMicrodumpExtraInfo(
|
||||
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
|
||||
|
||||
std::string buf;
|
||||
MappingList no_mappings;
|
||||
|
||||
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, true, 0);
|
||||
ASSERT_FALSE(ContainsMicrodump(buf));
|
||||
}
|
||||
|
||||
// Ensure that stack content does not contain an identifiable string if the
|
||||
// stack is sanitized.
|
||||
TEST(MicrodumpWriterTest, StringRemovedBySanitization) {
|
||||
const char kProductInfo[] = "MockProduct:42.0.2311.99";
|
||||
const char kBuildFingerprint[] =
|
||||
"aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys";
|
||||
const char kGPUFingerprint[] =
|
||||
"Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
|
||||
|
||||
const MicrodumpExtraInfo kMicrodumpExtraInfo(
|
||||
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
|
||||
|
||||
std::string buf;
|
||||
MappingList no_mappings;
|
||||
|
||||
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, false, 0u, true);
|
||||
ASSERT_TRUE(ContainsMicrodump(buf));
|
||||
ASSERT_FALSE(MicrodumpStackContains(buf, kIdentifiableString));
|
||||
}
|
||||
|
||||
// Ensure that stack content does contain an identifiable string if the
|
||||
// stack is not sanitized.
|
||||
TEST(MicrodumpWriterTest, StringPresentIfNotSanitized) {
|
||||
const char kProductInfo[] = "MockProduct:42.0.2311.99";
|
||||
const char kBuildFingerprint[] =
|
||||
"aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys";
|
||||
const char kGPUFingerprint[] =
|
||||
"Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
|
||||
|
||||
const MicrodumpExtraInfo kMicrodumpExtraInfo(
|
||||
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
|
||||
|
||||
std::string buf;
|
||||
MappingList no_mappings;
|
||||
|
||||
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, false, 0u, false);
|
||||
ASSERT_TRUE(ContainsMicrodump(buf));
|
||||
ASSERT_TRUE(MicrodumpStackContains(buf, kIdentifiableString));
|
||||
}
|
||||
|
||||
// Ensure that output occurs if the interest region is set, and
|
||||
// does overlap something on the stack.
|
||||
TEST(MicrodumpWriterTest, OutputIfInteresting) {
|
||||
const char kProductInfo[] = "MockProduct:42.0.2311.99";
|
||||
const char kBuildFingerprint[] =
|
||||
"aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys";
|
||||
const char kGPUFingerprint[] =
|
||||
"Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
|
||||
|
||||
const MicrodumpExtraInfo kMicrodumpExtraInfo(
|
||||
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
|
||||
|
||||
std::string buf;
|
||||
MappingList no_mappings;
|
||||
|
||||
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, true,
|
||||
reinterpret_cast<uintptr_t>(CrashAndGetMicrodump));
|
||||
ASSERT_TRUE(ContainsMicrodump(buf));
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf.get(), "V UNKNOWN:0.0.0.0"));
|
||||
}
|
||||
|
||||
// Ensure that the product info and build fingerprint metadata show up in the
|
||||
|
@ -381,40 +220,38 @@ TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) {
|
|||
"Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
|
||||
const MicrodumpExtraInfo kMicrodumpExtraInfo(
|
||||
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
|
||||
std::string buf;
|
||||
scoped_array<char> buf;
|
||||
MappingList no_mappings;
|
||||
|
||||
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf);
|
||||
ASSERT_TRUE(ContainsMicrodump(buf));
|
||||
CheckMicrodumpContents(buf, kMicrodumpExtraInfo);
|
||||
CheckMicrodumpContents(string(buf.get()), kMicrodumpExtraInfo);
|
||||
}
|
||||
|
||||
TEST(MicrodumpWriterTest, NoProductInfo) {
|
||||
const char kBuildFingerprint[] = "foobar";
|
||||
const char kGPUFingerprint[] = "bazqux";
|
||||
std::string buf;
|
||||
scoped_array<char> buf;
|
||||
MappingList no_mappings;
|
||||
|
||||
const MicrodumpExtraInfo kMicrodumpExtraInfoNoProductInfo(
|
||||
MakeMicrodumpExtraInfo(kBuildFingerprint, NULL, kGPUFingerprint));
|
||||
|
||||
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoProductInfo, &buf);
|
||||
ASSERT_TRUE(ContainsMicrodump(buf));
|
||||
CheckMicrodumpContents(buf, kBuildFingerprint, "UNKNOWN:0.0.0.0",
|
||||
kGPUFingerprint);
|
||||
CheckMicrodumpContents(string(buf.get()), kBuildFingerprint,
|
||||
"UNKNOWN:0.0.0.0", kGPUFingerprint);
|
||||
}
|
||||
|
||||
TEST(MicrodumpWriterTest, NoGPUInfo) {
|
||||
const char kProductInfo[] = "bazqux";
|
||||
const char kBuildFingerprint[] = "foobar";
|
||||
std::string buf;
|
||||
scoped_array<char> buf;
|
||||
MappingList no_mappings;
|
||||
|
||||
const MicrodumpExtraInfo kMicrodumpExtraInfoNoGPUInfo(
|
||||
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, NULL));
|
||||
|
||||
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoGPUInfo, &buf);
|
||||
ASSERT_TRUE(ContainsMicrodump(buf));
|
||||
CheckMicrodumpContents(buf, kBuildFingerprint, kProductInfo, "UNKNOWN");
|
||||
CheckMicrodumpContents(string(buf.get()), kBuildFingerprint,
|
||||
kProductInfo, "UNKNOWN");
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -212,7 +212,6 @@ bool LinuxCoreDumper::EnumerateThreads() {
|
|||
if (first_thread) {
|
||||
crash_thread_ = pid;
|
||||
crash_signal_ = status->pr_info.si_signo;
|
||||
crash_signal_code_ = status->pr_info.si_code;
|
||||
}
|
||||
first_thread = false;
|
||||
threads_.push_back(pid);
|
||||
|
|
|
@ -41,7 +41,7 @@ using namespace google_breakpad;
|
|||
|
||||
TEST(LinuxCoreDumperTest, GetMappingAbsolutePath) {
|
||||
const LinuxCoreDumper dumper(getpid(), "core", "/tmp", "/mnt/root");
|
||||
const MappingInfo mapping = {0, 0, {0, 0}, 0, false, "/usr/lib/libc.so"};
|
||||
const MappingInfo mapping = { 0, 0, 0, false, "/usr/lib/libc.so" };
|
||||
|
||||
char path[PATH_MAX];
|
||||
dumper.GetMappingAbsolutePath(mapping, path);
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
#include "common/linux/linux_libc_support.h"
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
#include "common/linux/safe_readlink.h"
|
||||
#include "google_breakpad/common/minidump_exception_linux.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
@ -86,15 +85,10 @@ inline static bool IsMappedFileOpenUnsafe(
|
|||
|
||||
namespace google_breakpad {
|
||||
|
||||
namespace {
|
||||
|
||||
bool MappingContainsAddress(const MappingInfo& mapping, uintptr_t address) {
|
||||
return mapping.system_mapping_info.start_addr <= address &&
|
||||
address < mapping.system_mapping_info.end_addr;
|
||||
}
|
||||
|
||||
#if defined(__CHROMEOS__)
|
||||
|
||||
namespace {
|
||||
|
||||
// Recover memory mappings before writing dump on ChromeOS
|
||||
//
|
||||
// On Linux, breakpad relies on /proc/[pid]/maps to associate symbols from
|
||||
|
@ -231,21 +225,20 @@ void CrOSPostProcessMappings(wasteful_vector<MappingInfo*>& mappings) {
|
|||
l = m + 1;
|
||||
}
|
||||
|
||||
// Shows the range that contains the entry point is
|
||||
// [first_start_addr, first_end_addr)
|
||||
size_t first_start_addr = mappings[0]->start_addr;
|
||||
size_t first_end_addr = mappings[0]->start_addr + mappings[0]->size;
|
||||
|
||||
// Put the out-of-order segment in order.
|
||||
std::rotate(mappings.begin(), mappings.begin() + 1, mappings.begin() + next);
|
||||
// Try to merge segments into the first.
|
||||
if (next < mappings.size()) {
|
||||
TryRecoverMappings(mappings[0], mappings[next]);
|
||||
if (next - 1 > 0)
|
||||
TryRecoverMappings(mappings[next - 1], mappings[0], mappings[next]);
|
||||
}
|
||||
|
||||
// Iterate through normal, sorted cases.
|
||||
// Normal case 1.
|
||||
for (size_t i = 0; i < mappings.size() - 1; i++)
|
||||
for (size_t i = 1; i < mappings.size() - 1; i++)
|
||||
TryRecoverMappings(mappings[i], mappings[i + 1]);
|
||||
|
||||
// Normal case 2.
|
||||
for (size_t i = 0; i < mappings.size() - 2; i++)
|
||||
for (size_t i = 1; i < mappings.size() - 2; i++)
|
||||
TryRecoverMappings(mappings[i], mappings[i + 1], mappings[i + 2]);
|
||||
|
||||
// Collect merged (size == 0) segments.
|
||||
|
@ -254,27 +247,10 @@ void CrOSPostProcessMappings(wasteful_vector<MappingInfo*>& mappings) {
|
|||
if (mappings[e]->size > 0)
|
||||
mappings[f++] = mappings[e];
|
||||
mappings.resize(f);
|
||||
|
||||
// The entry point is in the first mapping. We want to find the location
|
||||
// of the entry point after merging segment. To do this, we want to find
|
||||
// the mapping that covers the first mapping from the original mapping list.
|
||||
// If the mapping is not in the beginning, we move it to the begining via
|
||||
// a right rotate by using reverse iterators.
|
||||
for (l = 0; l < mappings.size(); l++) {
|
||||
if (mappings[l]->start_addr <= first_start_addr
|
||||
&& (mappings[l]->start_addr + mappings[l]->size >= first_end_addr))
|
||||
break;
|
||||
}
|
||||
if (l > 0) {
|
||||
r = mappings.size();
|
||||
std::rotate(mappings.rbegin() + r - l - 1, mappings.rbegin() + r - l,
|
||||
mappings.rend());
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __CHROMEOS__
|
||||
|
||||
} // namespace
|
||||
#endif // __CHROMEOS__
|
||||
|
||||
// All interesting auvx entry types are below AT_SYSINFO_EHDR
|
||||
#define AT_MAX AT_SYSINFO_EHDR
|
||||
|
@ -284,7 +260,6 @@ LinuxDumper::LinuxDumper(pid_t pid, const char* root_prefix)
|
|||
root_prefix_(root_prefix),
|
||||
crash_address_(0),
|
||||
crash_signal_(0),
|
||||
crash_signal_code_(0),
|
||||
crash_thread_(pid),
|
||||
threads_(&allocator_, 8),
|
||||
mappings_(&allocator_),
|
||||
|
@ -356,83 +331,6 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
|
|||
return success;
|
||||
}
|
||||
|
||||
void LinuxDumper::SetCrashInfoFromSigInfo(const siginfo_t& siginfo) {
|
||||
set_crash_address(reinterpret_cast<uintptr_t>(siginfo.si_addr));
|
||||
set_crash_signal(siginfo.si_signo);
|
||||
set_crash_signal_code(siginfo.si_code);
|
||||
}
|
||||
|
||||
const char* LinuxDumper::GetCrashSignalString() const {
|
||||
switch (static_cast<unsigned int>(crash_signal_)) {
|
||||
case MD_EXCEPTION_CODE_LIN_SIGHUP:
|
||||
return "SIGHUP";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGINT:
|
||||
return "SIGINT";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGQUIT:
|
||||
return "SIGQUIT";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGILL:
|
||||
return "SIGILL";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGTRAP:
|
||||
return "SIGTRAP";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGABRT:
|
||||
return "SIGABRT";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGBUS:
|
||||
return "SIGBUS";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGFPE:
|
||||
return "SIGFPE";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGKILL:
|
||||
return "SIGKILL";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGUSR1:
|
||||
return "SIGUSR1";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGSEGV:
|
||||
return "SIGSEGV";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGUSR2:
|
||||
return "SIGUSR2";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGPIPE:
|
||||
return "SIGPIPE";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGALRM:
|
||||
return "SIGALRM";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGTERM:
|
||||
return "SIGTERM";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGSTKFLT:
|
||||
return "SIGSTKFLT";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGCHLD:
|
||||
return "SIGCHLD";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGCONT:
|
||||
return "SIGCONT";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGSTOP:
|
||||
return "SIGSTOP";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGTSTP:
|
||||
return "SIGTSTP";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGTTIN:
|
||||
return "SIGTTIN";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGTTOU:
|
||||
return "SIGTTOU";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGURG:
|
||||
return "SIGURG";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGXCPU:
|
||||
return "SIGXCPU";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGXFSZ:
|
||||
return "SIGXFSZ";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGVTALRM:
|
||||
return "SIGVTALRM";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGPROF:
|
||||
return "SIGPROF";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGWINCH:
|
||||
return "SIGWINCH";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGIO:
|
||||
return "SIGIO";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGPWR:
|
||||
return "SIGPWR";
|
||||
case MD_EXCEPTION_CODE_LIN_SIGSYS:
|
||||
return "SIGSYS";
|
||||
case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED:
|
||||
return "DUMP_REQUESTED";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
bool LinuxDumper::GetMappingAbsolutePath(const MappingInfo& mapping,
|
||||
char path[PATH_MAX]) const {
|
||||
return my_strlcpy(path, root_prefix_, PATH_MAX) < PATH_MAX &&
|
||||
|
@ -449,16 +347,17 @@ bool ElfFileSoNameFromMappedFile(
|
|||
|
||||
const void* segment_start;
|
||||
size_t segment_size;
|
||||
if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC, &segment_start,
|
||||
&segment_size)) {
|
||||
int elf_class;
|
||||
if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC,
|
||||
&segment_start, &segment_size, &elf_class)) {
|
||||
// No dynamic section
|
||||
return false;
|
||||
}
|
||||
|
||||
const void* dynstr_start;
|
||||
size_t dynstr_size;
|
||||
if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB, &dynstr_start,
|
||||
&dynstr_size)) {
|
||||
if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB,
|
||||
&dynstr_start, &dynstr_size, &elf_class)) {
|
||||
// No dynstr section
|
||||
return false;
|
||||
}
|
||||
|
@ -647,10 +546,7 @@ bool LinuxDumper::EnumerateMappings() {
|
|||
}
|
||||
}
|
||||
MappingInfo* const module = new(allocator_) MappingInfo;
|
||||
mappings_.push_back(module);
|
||||
my_memset(module, 0, sizeof(MappingInfo));
|
||||
module->system_mapping_info.start_addr = start_addr;
|
||||
module->system_mapping_info.end_addr = end_addr;
|
||||
module->start_addr = start_addr;
|
||||
module->size = end_addr - start_addr;
|
||||
module->offset = offset;
|
||||
|
@ -660,32 +556,31 @@ bool LinuxDumper::EnumerateMappings() {
|
|||
if (l < sizeof(module->name))
|
||||
my_memcpy(module->name, name, l);
|
||||
}
|
||||
// If this is the entry-point mapping, and it's not already the
|
||||
// first one, then we need to make it be first. This is because
|
||||
// the minidump format assumes the first module is the one that
|
||||
// corresponds to the main executable (as codified in
|
||||
// processor/minidump.cc:MinidumpModuleList::GetMainModule()).
|
||||
if (entry_point_loc &&
|
||||
(entry_point_loc >=
|
||||
reinterpret_cast<void*>(module->start_addr)) &&
|
||||
(entry_point_loc <
|
||||
reinterpret_cast<void*>(module->start_addr+module->size)) &&
|
||||
!mappings_.empty()) {
|
||||
// push the module onto the front of the list.
|
||||
mappings_.resize(mappings_.size() + 1);
|
||||
for (size_t idx = mappings_.size() - 1; idx > 0; idx--)
|
||||
mappings_[idx] = mappings_[idx - 1];
|
||||
mappings_[0] = module;
|
||||
} else {
|
||||
mappings_.push_back(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
line_reader->PopLine(line_len);
|
||||
}
|
||||
|
||||
if (entry_point_loc) {
|
||||
for (size_t i = 0; i < mappings_.size(); ++i) {
|
||||
MappingInfo* module = mappings_[i];
|
||||
|
||||
// If this module contains the entry-point, and it's not already the first
|
||||
// one, then we need to make it be first. This is because the minidump
|
||||
// format assumes the first module is the one that corresponds to the main
|
||||
// executable (as codified in
|
||||
// processor/minidump.cc:MinidumpModuleList::GetMainModule()).
|
||||
if ((entry_point_loc >= reinterpret_cast<void*>(module->start_addr)) &&
|
||||
(entry_point_loc <
|
||||
reinterpret_cast<void*>(module->start_addr + module->size))) {
|
||||
for (size_t j = i; j > 0; j--)
|
||||
mappings_[j] = mappings_[j - 1];
|
||||
mappings_[0] = module;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sys_close(fd);
|
||||
|
||||
return !mappings_.empty();
|
||||
|
@ -825,126 +720,6 @@ bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
|
|||
return true;
|
||||
}
|
||||
|
||||
void LinuxDumper::SanitizeStackCopy(uint8_t* stack_copy, size_t stack_len,
|
||||
uintptr_t stack_pointer,
|
||||
uintptr_t sp_offset) {
|
||||
// We optimize the search for containing mappings in three ways:
|
||||
// 1) We expect that pointers into the stack mapping will be common, so
|
||||
// we cache that address range.
|
||||
// 2) The last referenced mapping is a reasonable predictor for the next
|
||||
// referenced mapping, so we test that first.
|
||||
// 3) We precompute a bitfield based upon bits 32:32-n of the start and
|
||||
// stop addresses, and use that to short circuit any values that can
|
||||
// not be pointers. (n=11)
|
||||
const uintptr_t defaced =
|
||||
#if defined(__LP64__)
|
||||
0x0defaced0defaced;
|
||||
#else
|
||||
0x0defaced;
|
||||
#endif
|
||||
// the bitfield length is 2^test_bits long.
|
||||
const unsigned int test_bits = 11;
|
||||
// byte length of the corresponding array.
|
||||
const unsigned int array_size = 1 << (test_bits - 3);
|
||||
const unsigned int array_mask = array_size - 1;
|
||||
// The amount to right shift pointers by. This captures the top bits
|
||||
// on 32 bit architectures. On 64 bit architectures this would be
|
||||
// uninformative so we take the same range of bits.
|
||||
const unsigned int shift = 32 - 11;
|
||||
const MappingInfo* last_hit_mapping = nullptr;
|
||||
const MappingInfo* hit_mapping = nullptr;
|
||||
const MappingInfo* stack_mapping = FindMappingNoBias(stack_pointer);
|
||||
// The magnitude below which integers are considered to be to be
|
||||
// 'small', and not constitute a PII risk. These are included to
|
||||
// avoid eliding useful register values.
|
||||
const ssize_t small_int_magnitude = 4096;
|
||||
|
||||
char could_hit_mapping[array_size];
|
||||
my_memset(could_hit_mapping, 0, array_size);
|
||||
|
||||
// Initialize the bitfield such that if the (pointer >> shift)'th
|
||||
// bit, modulo the bitfield size, is not set then there does not
|
||||
// exist a mapping in mappings_ that would contain that pointer.
|
||||
for (size_t i = 0; i < mappings_.size(); ++i) {
|
||||
if (!mappings_[i]->exec) continue;
|
||||
// For each mapping, work out the (unmodulo'ed) range of bits to
|
||||
// set.
|
||||
uintptr_t start = mappings_[i]->start_addr;
|
||||
uintptr_t end = start + mappings_[i]->size;
|
||||
start >>= shift;
|
||||
end >>= shift;
|
||||
for (size_t bit = start; bit <= end; ++bit) {
|
||||
// Set each bit in the range, applying the modulus.
|
||||
could_hit_mapping[(bit >> 3) & array_mask] |= 1 << (bit & 7);
|
||||
}
|
||||
}
|
||||
|
||||
// Zero memory that is below the current stack pointer.
|
||||
const uintptr_t offset =
|
||||
(sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
|
||||
if (offset) {
|
||||
my_memset(stack_copy, 0, offset);
|
||||
}
|
||||
|
||||
// Apply sanitization to each complete pointer-aligned word in the
|
||||
// stack.
|
||||
uint8_t* sp;
|
||||
for (sp = stack_copy + offset;
|
||||
sp <= stack_copy + stack_len - sizeof(uintptr_t);
|
||||
sp += sizeof(uintptr_t)) {
|
||||
uintptr_t addr;
|
||||
my_memcpy(&addr, sp, sizeof(uintptr_t));
|
||||
if (static_cast<intptr_t>(addr) <= small_int_magnitude &&
|
||||
static_cast<intptr_t>(addr) >= -small_int_magnitude) {
|
||||
continue;
|
||||
}
|
||||
if (stack_mapping && MappingContainsAddress(*stack_mapping, addr)) {
|
||||
continue;
|
||||
}
|
||||
if (last_hit_mapping && MappingContainsAddress(*last_hit_mapping, addr)) {
|
||||
continue;
|
||||
}
|
||||
uintptr_t test = addr >> shift;
|
||||
if (could_hit_mapping[(test >> 3) & array_mask] & (1 << (test & 7)) &&
|
||||
(hit_mapping = FindMappingNoBias(addr)) != nullptr &&
|
||||
hit_mapping->exec) {
|
||||
last_hit_mapping = hit_mapping;
|
||||
continue;
|
||||
}
|
||||
my_memcpy(sp, &defaced, sizeof(uintptr_t));
|
||||
}
|
||||
// Zero any partial word at the top of the stack, if alignment is
|
||||
// such that that is required.
|
||||
if (sp < stack_copy + stack_len) {
|
||||
my_memset(sp, 0, stack_copy + stack_len - sp);
|
||||
}
|
||||
}
|
||||
|
||||
bool LinuxDumper::StackHasPointerToMapping(const uint8_t* stack_copy,
|
||||
size_t stack_len,
|
||||
uintptr_t sp_offset,
|
||||
const MappingInfo& mapping) {
|
||||
// Loop over all stack words that would have been on the stack in
|
||||
// the target process (i.e. are word aligned, and at addresses >=
|
||||
// the stack pointer). Regardless of the alignment of |stack_copy|,
|
||||
// the memory starting at |stack_copy| + |offset| represents an
|
||||
// aligned word in the target process.
|
||||
const uintptr_t low_addr = mapping.system_mapping_info.start_addr;
|
||||
const uintptr_t high_addr = mapping.system_mapping_info.end_addr;
|
||||
const uintptr_t offset =
|
||||
(sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
|
||||
|
||||
for (const uint8_t* sp = stack_copy + offset;
|
||||
sp <= stack_copy + stack_len - sizeof(uintptr_t);
|
||||
sp += sizeof(uintptr_t)) {
|
||||
uintptr_t addr;
|
||||
my_memcpy(&addr, sp, sizeof(uintptr_t));
|
||||
if (low_addr <= addr && addr <= high_addr)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the mapping which the given memory address falls in.
|
||||
const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
|
||||
const uintptr_t addr = (uintptr_t) address;
|
||||
|
@ -958,19 +733,6 @@ const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// Find the mapping which the given memory address falls in. Uses the
|
||||
// unadjusted mapping address range from the kernel, rather than the
|
||||
// biased range.
|
||||
const MappingInfo* LinuxDumper::FindMappingNoBias(uintptr_t address) const {
|
||||
for (size_t i = 0; i < mappings_.size(); ++i) {
|
||||
if (address >= mappings_[i]->system_mapping_info.start_addr &&
|
||||
address < mappings_[i]->system_mapping_info.end_addr) {
|
||||
return mappings_[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
|
||||
static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1;
|
||||
|
||||
|
|
|
@ -99,22 +99,10 @@ class LinuxDumper {
|
|||
// Returns true on success. One must have called |ThreadsSuspend| first.
|
||||
virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info) = 0;
|
||||
|
||||
size_t GetMainThreadIndex() const {
|
||||
for (size_t i = 0; i < threads_.size(); ++i) {
|
||||
if (threads_[i] == pid_) return i;
|
||||
}
|
||||
return -1u;
|
||||
}
|
||||
|
||||
// These are only valid after a call to |Init|.
|
||||
const wasteful_vector<pid_t> &threads() { return threads_; }
|
||||
const wasteful_vector<MappingInfo*> &mappings() { return mappings_; }
|
||||
const MappingInfo* FindMapping(const void* address) const;
|
||||
// Find the mapping which the given memory address falls in. Unlike
|
||||
// FindMapping, this method uses the unadjusted mapping address
|
||||
// ranges from the kernel, rather than the ranges that have had the
|
||||
// load bias applied.
|
||||
const MappingInfo* FindMappingNoBias(uintptr_t address) const;
|
||||
const wasteful_vector<elf_aux_val_t>& auxv() { return auxv_; }
|
||||
|
||||
// Find a block of memory to take as the stack given the top of stack pointer.
|
||||
|
@ -123,32 +111,6 @@ class LinuxDumper {
|
|||
// stack_top: the current top of the stack
|
||||
bool GetStackInfo(const void** stack, size_t* stack_len, uintptr_t stack_top);
|
||||
|
||||
// Sanitize a copy of the stack by overwriting words that are not
|
||||
// pointers with a sentinel (0x0defaced).
|
||||
// stack_copy: a copy of the stack to sanitize. |stack_copy| might
|
||||
// not be word aligned, but it represents word aligned
|
||||
// data copied from another location.
|
||||
// stack_len: the length of the allocation pointed to by |stack_copy|.
|
||||
// stack_pointer: the address of the stack pointer (used to locate
|
||||
// the stack mapping, as an optimization).
|
||||
// sp_offset: the offset relative to stack_copy that reflects the
|
||||
// current value of the stack pointer.
|
||||
void SanitizeStackCopy(uint8_t* stack_copy, size_t stack_len,
|
||||
uintptr_t stack_pointer, uintptr_t sp_offset);
|
||||
|
||||
// Test whether |stack_copy| contains a pointer-aligned word that
|
||||
// could be an address within a given mapping.
|
||||
// stack_copy: a copy of the stack to check. |stack_copy| might
|
||||
// not be word aligned, but it represents word aligned
|
||||
// data copied from another location.
|
||||
// stack_len: the length of the allocation pointed to by |stack_copy|.
|
||||
// sp_offset: the offset relative to stack_copy that reflects the
|
||||
// current value of the stack pointer.
|
||||
// mapping: the mapping against which to test stack words.
|
||||
bool StackHasPointerToMapping(const uint8_t* stack_copy, size_t stack_len,
|
||||
uintptr_t sp_offset,
|
||||
const MappingInfo& mapping);
|
||||
|
||||
PageAllocator* allocator() { return &allocator_; }
|
||||
|
||||
// Copy content of |length| bytes from a given process |child|,
|
||||
|
@ -170,8 +132,6 @@ class LinuxDumper {
|
|||
unsigned int mapping_id,
|
||||
wasteful_vector<uint8_t>& identifier);
|
||||
|
||||
void SetCrashInfoFromSigInfo(const siginfo_t& siginfo);
|
||||
|
||||
uintptr_t crash_address() const { return crash_address_; }
|
||||
void set_crash_address(uintptr_t crash_address) {
|
||||
crash_address_ = crash_address;
|
||||
|
@ -179,10 +139,6 @@ class LinuxDumper {
|
|||
|
||||
int crash_signal() const { return crash_signal_; }
|
||||
void set_crash_signal(int crash_signal) { crash_signal_ = crash_signal; }
|
||||
const char* GetCrashSignalString() const;
|
||||
|
||||
void set_crash_signal_code(int code) { crash_signal_code_ = code; }
|
||||
int crash_signal_code() const { return crash_signal_code_; }
|
||||
|
||||
pid_t crash_thread() const { return crash_thread_; }
|
||||
void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; }
|
||||
|
@ -233,9 +189,6 @@ class LinuxDumper {
|
|||
// Signal that terminated the crashed process.
|
||||
int crash_signal_;
|
||||
|
||||
// The code associated with |crash_signal_|.
|
||||
int crash_signal_code_;
|
||||
|
||||
// ID of the crashed thread.
|
||||
pid_t crash_thread_;
|
||||
|
||||
|
|
|
@ -57,15 +57,14 @@
|
|||
|
||||
void *thread_function(void *data) {
|
||||
int pipefd = *static_cast<int *>(data);
|
||||
volatile pid_t* thread_id = new pid_t;
|
||||
*thread_id = syscall(__NR_gettid);
|
||||
volatile pid_t thread_id = syscall(__NR_gettid);
|
||||
// Signal parent that a thread has started.
|
||||
uint8_t byte = 1;
|
||||
if (write(pipefd, &byte, sizeof(byte)) != sizeof(byte)) {
|
||||
perror("ERROR: parent notification failed");
|
||||
return NULL;
|
||||
}
|
||||
register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = thread_id;
|
||||
register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = &thread_id;
|
||||
while (true)
|
||||
asm volatile ("" : : "r" (thread_id_ptr));
|
||||
return NULL;
|
||||
|
|
|
@ -149,50 +149,6 @@ bool LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool LinuxPtraceDumper::ReadRegisterSet(ThreadInfo* info, pid_t tid)
|
||||
{
|
||||
#ifdef PTRACE_GETREGSET
|
||||
struct iovec io;
|
||||
info->GetGeneralPurposeRegisters(&io.iov_base, &io.iov_len);
|
||||
if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
info->GetFloatingPointRegisters(&io.iov_base, &io.iov_len);
|
||||
if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LinuxPtraceDumper::ReadRegisters(ThreadInfo* info, pid_t tid) {
|
||||
#ifdef PTRACE_GETREGS
|
||||
void* gp_addr;
|
||||
info->GetGeneralPurposeRegisters(&gp_addr, NULL);
|
||||
if (sys_ptrace(PTRACE_GETREGS, tid, NULL, gp_addr) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !(defined(__ANDROID__) && defined(__ARM_EABI__))
|
||||
// When running an arm build on an arm64 device, attempting to get the
|
||||
// floating point registers fails. On Android, the floating point registers
|
||||
// aren't written to the cpu context anyway, so just don't get them here.
|
||||
// See http://crbug.com/508324
|
||||
void* fp_addr;
|
||||
info->GetFloatingPointRegisters(&fp_addr, NULL);
|
||||
if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, fp_addr) == -1) {
|
||||
return false;
|
||||
}
|
||||
#endif // !(defined(__ANDROID__) && defined(__ARM_EABI__))
|
||||
return true;
|
||||
#else // PTRACE_GETREGS
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Read thread info from /proc/$pid/status.
|
||||
// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable,
|
||||
// these members are set to -1. Returns true iff all three members are
|
||||
|
@ -232,12 +188,37 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
|
|||
if (info->ppid == -1 || info->tgid == -1)
|
||||
return false;
|
||||
|
||||
if (!ReadRegisterSet(info, tid)) {
|
||||
if (!ReadRegisters(info, tid)) {
|
||||
return false;
|
||||
}
|
||||
#ifdef PTRACE_GETREGSET
|
||||
struct iovec io;
|
||||
info->GetGeneralPurposeRegisters(&io.iov_base, &io.iov_len);
|
||||
if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
info->GetFloatingPointRegisters(&io.iov_base, &io.iov_len);
|
||||
if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) {
|
||||
return false;
|
||||
}
|
||||
#else // PTRACE_GETREGSET
|
||||
void* gp_addr;
|
||||
info->GetGeneralPurposeRegisters(&gp_addr, NULL);
|
||||
if (sys_ptrace(PTRACE_GETREGS, tid, NULL, gp_addr) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !(defined(__ANDROID__) && defined(__ARM_EABI__))
|
||||
// When running an arm build on an arm64 device, attempting to get the
|
||||
// floating point registers fails. On Android, the floating point registers
|
||||
// aren't written to the cpu context anyway, so just don't get them here.
|
||||
// See http://crbug.com/508324
|
||||
void* fp_addr;
|
||||
info->GetFloatingPointRegisters(&fp_addr, NULL);
|
||||
if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, fp_addr) == -1) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif // PTRACE_GETREGSET
|
||||
|
||||
#if defined(__i386)
|
||||
#if !defined(bit_FXSAVE) // e.g. Clang
|
||||
#define bit_FXSAVE bit_FXSR
|
||||
|
@ -268,8 +249,6 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
|
|||
#endif
|
||||
|
||||
#if defined(__mips__)
|
||||
sys_ptrace(PTRACE_PEEKUSER, tid,
|
||||
reinterpret_cast<void*>(PC), &info->mcontext.pc);
|
||||
sys_ptrace(PTRACE_PEEKUSER, tid,
|
||||
reinterpret_cast<void*>(DSP_BASE), &info->mcontext.hi1);
|
||||
sys_ptrace(PTRACE_PEEKUSER, tid,
|
||||
|
|
|
@ -85,15 +85,6 @@ class LinuxPtraceDumper : public LinuxDumper {
|
|||
private:
|
||||
// Set to true if all threads of the crashed process are suspended.
|
||||
bool threads_suspended_;
|
||||
|
||||
// Read the tracee's registers on kernel with PTRACE_GETREGSET support.
|
||||
// Returns false if PTRACE_GETREGSET is not defined.
|
||||
// Returns true on success.
|
||||
bool ReadRegisterSet(ThreadInfo* info, pid_t tid);
|
||||
|
||||
// Read the tracee's registers on kernel with PTRACE_GETREGS support.
|
||||
// Returns true on success.
|
||||
bool ReadRegisters(ThreadInfo* info, pid_t tid);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -66,63 +66,6 @@ using namespace google_breakpad;
|
|||
|
||||
namespace {
|
||||
|
||||
pid_t SetupChildProcess(int number_of_threads) {
|
||||
char kNumberOfThreadsArgument[2];
|
||||
sprintf(kNumberOfThreadsArgument, "%d", number_of_threads);
|
||||
|
||||
int fds[2];
|
||||
EXPECT_NE(-1, pipe(fds));
|
||||
|
||||
pid_t child_pid = fork();
|
||||
if (child_pid == 0) {
|
||||
// In child process.
|
||||
close(fds[0]);
|
||||
|
||||
string helper_path(GetHelperBinary());
|
||||
if (helper_path.empty()) {
|
||||
fprintf(stderr, "Couldn't find helper binary\n");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
// Pass the pipe fd and the number of threads as arguments.
|
||||
char pipe_fd_string[8];
|
||||
sprintf(pipe_fd_string, "%d", fds[1]);
|
||||
execl(helper_path.c_str(),
|
||||
"linux_dumper_unittest_helper",
|
||||
pipe_fd_string,
|
||||
kNumberOfThreadsArgument,
|
||||
NULL);
|
||||
// Kill if we get here.
|
||||
printf("Errno from exec: %d", errno);
|
||||
std::string err_str = "Exec of " + helper_path + " failed";
|
||||
perror(err_str.c_str());
|
||||
_exit(1);
|
||||
}
|
||||
close(fds[1]);
|
||||
|
||||
// Wait for all child threads to indicate that they have started
|
||||
for (int threads = 0; threads < number_of_threads; threads++) {
|
||||
struct pollfd pfd;
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
pfd.fd = fds[0];
|
||||
pfd.events = POLLIN | POLLERR;
|
||||
|
||||
const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
|
||||
EXPECT_EQ(1, r);
|
||||
EXPECT_TRUE(pfd.revents & POLLIN);
|
||||
uint8_t junk;
|
||||
EXPECT_EQ(read(fds[0], &junk, sizeof(junk)),
|
||||
static_cast<ssize_t>(sizeof(junk)));
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
// There is a race here because we may stop a child thread before
|
||||
// it is actually running the busy loop. Empirically this sleep
|
||||
// is sufficient to avoid the race.
|
||||
usleep(100000);
|
||||
return child_pid;
|
||||
}
|
||||
|
||||
typedef wasteful_vector<uint8_t> id_vector;
|
||||
typedef testing::Test LinuxPtraceDumperTest;
|
||||
|
||||
|
@ -427,9 +370,58 @@ TEST_F(LinuxPtraceDumperChildTest, FileIDsMatch) {
|
|||
|
||||
TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) {
|
||||
static const int kNumberOfThreadsInHelperProgram = 5;
|
||||
char kNumberOfThreadsArgument[2];
|
||||
sprintf(kNumberOfThreadsArgument, "%d", kNumberOfThreadsInHelperProgram);
|
||||
|
||||
pid_t child_pid = SetupChildProcess(kNumberOfThreadsInHelperProgram);
|
||||
ASSERT_NE(child_pid, -1);
|
||||
int fds[2];
|
||||
ASSERT_NE(-1, pipe(fds));
|
||||
|
||||
pid_t child_pid = fork();
|
||||
if (child_pid == 0) {
|
||||
// In child process.
|
||||
close(fds[0]);
|
||||
|
||||
string helper_path(GetHelperBinary());
|
||||
if (helper_path.empty()) {
|
||||
FAIL() << "Couldn't find helper binary";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Pass the pipe fd and the number of threads as arguments.
|
||||
char pipe_fd_string[8];
|
||||
sprintf(pipe_fd_string, "%d", fds[1]);
|
||||
execl(helper_path.c_str(),
|
||||
"linux_dumper_unittest_helper",
|
||||
pipe_fd_string,
|
||||
kNumberOfThreadsArgument,
|
||||
NULL);
|
||||
// Kill if we get here.
|
||||
printf("Errno from exec: %d", errno);
|
||||
FAIL() << "Exec of " << helper_path << " failed: " << strerror(errno);
|
||||
exit(0);
|
||||
}
|
||||
close(fds[1]);
|
||||
|
||||
// Wait for all child threads to indicate that they have started
|
||||
for (int threads = 0; threads < kNumberOfThreadsInHelperProgram; threads++) {
|
||||
struct pollfd pfd;
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
pfd.fd = fds[0];
|
||||
pfd.events = POLLIN | POLLERR;
|
||||
|
||||
const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
|
||||
ASSERT_EQ(1, r);
|
||||
ASSERT_TRUE(pfd.revents & POLLIN);
|
||||
uint8_t junk;
|
||||
ASSERT_EQ(read(fds[0], &junk, sizeof(junk)),
|
||||
static_cast<ssize_t>(sizeof(junk)));
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
// There is a race here because we may stop a child thread before
|
||||
// it is actually running the busy loop. Empirically this sleep
|
||||
// is sufficient to avoid the race.
|
||||
usleep(100000);
|
||||
|
||||
// Children are ready now.
|
||||
LinuxPtraceDumper dumper(child_pid);
|
||||
|
@ -476,99 +468,3 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) {
|
|||
ASSERT_TRUE(WIFSIGNALED(status));
|
||||
ASSERT_EQ(SIGKILL, WTERMSIG(status));
|
||||
}
|
||||
|
||||
TEST_F(LinuxPtraceDumperTest, SanitizeStackCopy) {
|
||||
static const int kNumberOfThreadsInHelperProgram = 1;
|
||||
|
||||
pid_t child_pid = SetupChildProcess(kNumberOfThreadsInHelperProgram);
|
||||
ASSERT_NE(child_pid, -1);
|
||||
|
||||
LinuxPtraceDumper dumper(child_pid);
|
||||
ASSERT_TRUE(dumper.Init());
|
||||
EXPECT_TRUE(dumper.ThreadsSuspend());
|
||||
|
||||
ThreadInfo thread_info;
|
||||
EXPECT_TRUE(dumper.GetThreadInfoByIndex(0, &thread_info));
|
||||
|
||||
const uintptr_t defaced =
|
||||
#if defined(__LP64__)
|
||||
0x0defaced0defaced;
|
||||
#else
|
||||
0x0defaced;
|
||||
#endif
|
||||
|
||||
uintptr_t simulated_stack[2];
|
||||
|
||||
// Pointers into the stack shouldn't be sanitized.
|
||||
memset(simulated_stack, 0xff, sizeof(simulated_stack));
|
||||
simulated_stack[1] = thread_info.stack_pointer;
|
||||
dumper.SanitizeStackCopy(reinterpret_cast<uint8_t*>(&simulated_stack),
|
||||
sizeof(simulated_stack), thread_info.stack_pointer,
|
||||
sizeof(uintptr_t));
|
||||
ASSERT_NE(simulated_stack[1], defaced);
|
||||
|
||||
// Memory prior to the stack pointer should be cleared.
|
||||
ASSERT_EQ(simulated_stack[0], 0u);
|
||||
|
||||
// Small integers should not be sanitized.
|
||||
for (int i = -4096; i <= 4096; ++i) {
|
||||
memset(simulated_stack, 0, sizeof(simulated_stack));
|
||||
simulated_stack[0] = static_cast<uintptr_t>(i);
|
||||
dumper.SanitizeStackCopy(reinterpret_cast<uint8_t*>(&simulated_stack),
|
||||
sizeof(simulated_stack), thread_info.stack_pointer,
|
||||
0u);
|
||||
ASSERT_NE(simulated_stack[0], defaced);
|
||||
}
|
||||
|
||||
// The instruction pointer definitely should point into an executable mapping.
|
||||
const MappingInfo* mapping_info = dumper.FindMappingNoBias(
|
||||
reinterpret_cast<uintptr_t>(thread_info.GetInstructionPointer()));
|
||||
ASSERT_NE(mapping_info, nullptr);
|
||||
ASSERT_TRUE(mapping_info->exec);
|
||||
|
||||
// Pointers to code shouldn't be sanitized.
|
||||
memset(simulated_stack, 0, sizeof(simulated_stack));
|
||||
simulated_stack[1] = thread_info.GetInstructionPointer();
|
||||
dumper.SanitizeStackCopy(reinterpret_cast<uint8_t*>(&simulated_stack),
|
||||
sizeof(simulated_stack), thread_info.stack_pointer,
|
||||
0u);
|
||||
ASSERT_NE(simulated_stack[0], defaced);
|
||||
|
||||
// String fragments should be sanitized.
|
||||
memcpy(simulated_stack, "abcdefghijklmnop", sizeof(simulated_stack));
|
||||
dumper.SanitizeStackCopy(reinterpret_cast<uint8_t*>(&simulated_stack),
|
||||
sizeof(simulated_stack), thread_info.stack_pointer,
|
||||
0u);
|
||||
ASSERT_EQ(simulated_stack[0], defaced);
|
||||
ASSERT_EQ(simulated_stack[1], defaced);
|
||||
|
||||
// Heap pointers should be sanititzed.
|
||||
#if defined(__ARM_EABI__)
|
||||
uintptr_t heap_addr = thread_info.regs.uregs[3];
|
||||
#elif defined(__aarch64__)
|
||||
uintptr_t heap_addr = thread_info.regs.regs[3];
|
||||
#elif defined(__i386)
|
||||
uintptr_t heap_addr = thread_info.regs.ecx;
|
||||
#elif defined(__x86_64)
|
||||
uintptr_t heap_addr = thread_info.regs.rcx;
|
||||
#elif defined(__mips__)
|
||||
uintptr_t heap_addr = thread_info.mcontext.gregs[1];
|
||||
#else
|
||||
#error This test has not been ported to this platform.
|
||||
#endif
|
||||
memset(simulated_stack, 0, sizeof(simulated_stack));
|
||||
simulated_stack[0] = heap_addr;
|
||||
dumper.SanitizeStackCopy(reinterpret_cast<uint8_t*>(&simulated_stack),
|
||||
sizeof(simulated_stack), thread_info.stack_pointer,
|
||||
0u);
|
||||
ASSERT_EQ(simulated_stack[0], defaced);
|
||||
|
||||
EXPECT_TRUE(dumper.ThreadsResume());
|
||||
kill(child_pid, SIGKILL);
|
||||
|
||||
// Reap child.
|
||||
int status;
|
||||
ASSERT_NE(-1, HANDLE_EINTR(waitpid(child_pid, &status, 0)));
|
||||
ASSERT_TRUE(WIFSIGNALED(status));
|
||||
ASSERT_EQ(SIGKILL, WTERMSIG(status));
|
||||
}
|
||||
|
|
|
@ -129,9 +129,6 @@ class MinidumpWriter {
|
|||
const ExceptionHandler::CrashContext* context,
|
||||
const MappingList& mappings,
|
||||
const AppMemoryList& appmem,
|
||||
bool skip_stacks_if_mapping_unreferenced,
|
||||
uintptr_t principal_mapping_address,
|
||||
bool sanitize_stacks,
|
||||
LinuxDumper* dumper)
|
||||
: fd_(minidump_fd),
|
||||
path_(minidump_path),
|
||||
|
@ -143,12 +140,7 @@ class MinidumpWriter {
|
|||
minidump_size_limit_(-1),
|
||||
memory_blocks_(dumper_->allocator()),
|
||||
mapping_list_(mappings),
|
||||
app_memory_list_(appmem),
|
||||
skip_stacks_if_mapping_unreferenced_(
|
||||
skip_stacks_if_mapping_unreferenced),
|
||||
principal_mapping_address_(principal_mapping_address),
|
||||
principal_mapping_(nullptr),
|
||||
sanitize_stacks_(sanitize_stacks) {
|
||||
app_memory_list_(appmem) {
|
||||
// Assert there should be either a valid fd or a valid path, not both.
|
||||
assert(fd_ != -1 || minidump_path);
|
||||
assert(fd_ == -1 || !minidump_path);
|
||||
|
@ -158,22 +150,12 @@ class MinidumpWriter {
|
|||
if (!dumper_->Init())
|
||||
return false;
|
||||
|
||||
if (!dumper_->ThreadsSuspend() || !dumper_->LateInit())
|
||||
return false;
|
||||
|
||||
if (skip_stacks_if_mapping_unreferenced_) {
|
||||
principal_mapping_ =
|
||||
dumper_->FindMappingNoBias(principal_mapping_address_);
|
||||
if (!CrashingThreadReferencesPrincipalMapping())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fd_ != -1)
|
||||
minidump_writer_.SetFile(fd_);
|
||||
else if (!minidump_writer_.Open(path_))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return dumper_->ThreadsSuspend() && dumper_->LateInit();
|
||||
}
|
||||
|
||||
~MinidumpWriter() {
|
||||
|
@ -184,38 +166,6 @@ class MinidumpWriter {
|
|||
dumper_->ThreadsResume();
|
||||
}
|
||||
|
||||
bool CrashingThreadReferencesPrincipalMapping() {
|
||||
if (!ucontext_ || !principal_mapping_)
|
||||
return false;
|
||||
|
||||
const uintptr_t low_addr =
|
||||
principal_mapping_->system_mapping_info.start_addr;
|
||||
const uintptr_t high_addr =
|
||||
principal_mapping_->system_mapping_info.end_addr;
|
||||
|
||||
const uintptr_t stack_pointer = UContextReader::GetStackPointer(ucontext_);
|
||||
const uintptr_t pc = UContextReader::GetInstructionPointer(ucontext_);
|
||||
|
||||
if (pc >= low_addr && pc < high_addr)
|
||||
return true;
|
||||
|
||||
uint8_t* stack_copy;
|
||||
const void* stack;
|
||||
size_t stack_len;
|
||||
|
||||
if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer))
|
||||
return false;
|
||||
|
||||
stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
|
||||
dumper_->CopyFromProcess(stack_copy, GetCrashThread(), stack, stack_len);
|
||||
|
||||
uintptr_t stack_pointer_offset =
|
||||
stack_pointer - reinterpret_cast<uintptr_t>(stack);
|
||||
|
||||
return dumper_->StackHasPointerToMapping(
|
||||
stack_copy, stack_len, stack_pointer_offset, *principal_mapping_);
|
||||
}
|
||||
|
||||
bool Dump() {
|
||||
// A minidump file contains a number of tagged streams. This is the number
|
||||
// of stream which we write.
|
||||
|
@ -315,16 +265,12 @@ class MinidumpWriter {
|
|||
}
|
||||
|
||||
bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer,
|
||||
uintptr_t pc, int max_stack_len, uint8_t** stack_copy) {
|
||||
int max_stack_len, uint8_t** stack_copy) {
|
||||
*stack_copy = NULL;
|
||||
const void* stack;
|
||||
size_t stack_len;
|
||||
|
||||
thread->stack.start_of_memory_range = stack_pointer;
|
||||
thread->stack.memory.data_size = 0;
|
||||
thread->stack.memory.rva = minidump_writer_.position();
|
||||
|
||||
if (dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
|
||||
UntypedMDRVA memory(&minidump_writer_);
|
||||
if (max_stack_len >= 0 &&
|
||||
stack_len > static_cast<unsigned int>(max_stack_len)) {
|
||||
stack_len = max_stack_len;
|
||||
|
@ -337,38 +283,20 @@ class MinidumpWriter {
|
|||
}
|
||||
stack = reinterpret_cast<const void*>(int_stack);
|
||||
}
|
||||
if (!memory.Allocate(stack_len))
|
||||
return false;
|
||||
*stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
|
||||
dumper_->CopyFromProcess(*stack_copy, thread->thread_id, stack,
|
||||
stack_len);
|
||||
|
||||
uintptr_t stack_pointer_offset =
|
||||
stack_pointer - reinterpret_cast<uintptr_t>(stack);
|
||||
if (skip_stacks_if_mapping_unreferenced_) {
|
||||
if (!principal_mapping_) {
|
||||
return true;
|
||||
}
|
||||
uintptr_t low_addr = principal_mapping_->system_mapping_info.start_addr;
|
||||
uintptr_t high_addr = principal_mapping_->system_mapping_info.end_addr;
|
||||
if ((pc < low_addr || pc > high_addr) &&
|
||||
!dumper_->StackHasPointerToMapping(*stack_copy, stack_len,
|
||||
stack_pointer_offset,
|
||||
*principal_mapping_)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (sanitize_stacks_) {
|
||||
dumper_->SanitizeStackCopy(*stack_copy, stack_len, stack_pointer,
|
||||
stack_pointer_offset);
|
||||
}
|
||||
|
||||
UntypedMDRVA memory(&minidump_writer_);
|
||||
if (!memory.Allocate(stack_len))
|
||||
return false;
|
||||
memory.Copy(*stack_copy, stack_len);
|
||||
thread->stack.start_of_memory_range = reinterpret_cast<uintptr_t>(stack);
|
||||
thread->stack.start_of_memory_range =
|
||||
reinterpret_cast<uintptr_t>(stack);
|
||||
thread->stack.memory = memory.location();
|
||||
memory_blocks_.push_back(thread->stack);
|
||||
} else {
|
||||
thread->stack.start_of_memory_range = stack_pointer;
|
||||
thread->stack.memory.data_size = 0;
|
||||
thread->stack.memory.rva = minidump_writer_.position();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -415,9 +343,7 @@ class MinidumpWriter {
|
|||
!dumper_->IsPostMortem()) {
|
||||
uint8_t* stack_copy;
|
||||
const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_);
|
||||
if (!FillThreadStack(&thread, stack_ptr,
|
||||
UContextReader::GetInstructionPointer(ucontext_),
|
||||
-1, &stack_copy))
|
||||
if (!FillThreadStack(&thread, stack_ptr, -1, &stack_copy))
|
||||
return false;
|
||||
|
||||
// Copy 256 bytes around crashing instruction pointer to minidump.
|
||||
|
@ -483,9 +409,8 @@ class MinidumpWriter {
|
|||
int max_stack_len = -1; // default to no maximum for this thread
|
||||
if (minidump_size_limit_ >= 0 && i >= kLimitBaseThreadCount)
|
||||
max_stack_len = extra_thread_stack_len;
|
||||
if (!FillThreadStack(&thread, info.stack_pointer,
|
||||
info.GetInstructionPointer(), max_stack_len,
|
||||
&stack_copy))
|
||||
if (!FillThreadStack(&thread, info.stack_pointer, max_stack_len,
|
||||
&stack_copy))
|
||||
return false;
|
||||
|
||||
TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
|
||||
|
@ -701,18 +626,15 @@ class MinidumpWriter {
|
|||
TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
|
||||
if (!exc.Allocate())
|
||||
return false;
|
||||
|
||||
MDRawExceptionStream* stream = exc.get();
|
||||
my_memset(stream, 0, sizeof(MDRawExceptionStream));
|
||||
my_memset(exc.get(), 0, sizeof(MDRawExceptionStream));
|
||||
|
||||
dirent->stream_type = MD_EXCEPTION_STREAM;
|
||||
dirent->location = exc.location();
|
||||
|
||||
stream->thread_id = GetCrashThread();
|
||||
stream->exception_record.exception_code = dumper_->crash_signal();
|
||||
stream->exception_record.exception_flags = dumper_->crash_signal_code();
|
||||
stream->exception_record.exception_address = dumper_->crash_address();
|
||||
stream->thread_context = crashing_thread_context_;
|
||||
exc.get()->thread_id = GetCrashThread();
|
||||
exc.get()->exception_record.exception_code = dumper_->crash_signal();
|
||||
exc.get()->exception_record.exception_address = dumper_->crash_address();
|
||||
exc.get()->thread_context = crashing_thread_context_;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1342,13 +1264,6 @@ class MinidumpWriter {
|
|||
// Additional memory regions to be included in the dump,
|
||||
// provided by the caller.
|
||||
const AppMemoryList& app_memory_list_;
|
||||
// If set, skip recording any threads that do not reference the
|
||||
// mapping containing principal_mapping_address_.
|
||||
bool skip_stacks_if_mapping_unreferenced_;
|
||||
uintptr_t principal_mapping_address_;
|
||||
const MappingInfo* principal_mapping_;
|
||||
// If true, apply stack sanitization to stored stack data.
|
||||
bool sanitize_stacks_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1358,22 +1273,20 @@ bool WriteMinidumpImpl(const char* minidump_path,
|
|||
pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
const AppMemoryList& appmem,
|
||||
bool skip_stacks_if_mapping_unreferenced,
|
||||
uintptr_t principal_mapping_address,
|
||||
bool sanitize_stacks) {
|
||||
const AppMemoryList& appmem) {
|
||||
LinuxPtraceDumper dumper(crashing_process);
|
||||
const ExceptionHandler::CrashContext* context = NULL;
|
||||
if (blob) {
|
||||
if (blob_size != sizeof(ExceptionHandler::CrashContext))
|
||||
return false;
|
||||
context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
|
||||
dumper.SetCrashInfoFromSigInfo(context->siginfo);
|
||||
dumper.set_crash_address(
|
||||
reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
|
||||
dumper.set_crash_signal(context->siginfo.si_signo);
|
||||
dumper.set_crash_thread(context->tid);
|
||||
}
|
||||
MinidumpWriter writer(minidump_path, minidump_fd, context, mappings,
|
||||
appmem, skip_stacks_if_mapping_unreferenced,
|
||||
principal_mapping_address, sanitize_stacks, &dumper);
|
||||
appmem, &dumper);
|
||||
// Set desired limit for file size of minidump (-1 means no limit).
|
||||
writer.set_minidump_size_limit(minidump_size_limit);
|
||||
if (!writer.Init())
|
||||
|
@ -1386,29 +1299,17 @@ bool WriteMinidumpImpl(const char* minidump_path,
|
|||
namespace google_breakpad {
|
||||
|
||||
bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
bool skip_stacks_if_mapping_unreferenced,
|
||||
uintptr_t principal_mapping_address,
|
||||
bool sanitize_stacks) {
|
||||
const void* blob, size_t blob_size) {
|
||||
return WriteMinidumpImpl(minidump_path, -1, -1,
|
||||
crashing_process, blob, blob_size,
|
||||
MappingList(), AppMemoryList(),
|
||||
skip_stacks_if_mapping_unreferenced,
|
||||
principal_mapping_address,
|
||||
sanitize_stacks);
|
||||
MappingList(), AppMemoryList());
|
||||
}
|
||||
|
||||
bool WriteMinidump(int minidump_fd, pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
bool skip_stacks_if_mapping_unreferenced,
|
||||
uintptr_t principal_mapping_address,
|
||||
bool sanitize_stacks) {
|
||||
const void* blob, size_t blob_size) {
|
||||
return WriteMinidumpImpl(NULL, minidump_fd, -1,
|
||||
crashing_process, blob, blob_size,
|
||||
MappingList(), AppMemoryList(),
|
||||
skip_stacks_if_mapping_unreferenced,
|
||||
principal_mapping_address,
|
||||
sanitize_stacks);
|
||||
MappingList(), AppMemoryList());
|
||||
}
|
||||
|
||||
bool WriteMinidump(const char* minidump_path, pid_t process,
|
||||
|
@ -1418,7 +1319,7 @@ bool WriteMinidump(const char* minidump_path, pid_t process,
|
|||
dumper.set_crash_signal(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED);
|
||||
dumper.set_crash_thread(process_blamed_thread);
|
||||
MinidumpWriter writer(minidump_path, -1, NULL, MappingList(),
|
||||
AppMemoryList(), false, 0, false, &dumper);
|
||||
AppMemoryList(), &dumper);
|
||||
if (!writer.Init())
|
||||
return false;
|
||||
return writer.Dump();
|
||||
|
@ -1427,71 +1328,46 @@ bool WriteMinidump(const char* minidump_path, pid_t process,
|
|||
bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
const AppMemoryList& appmem,
|
||||
bool skip_stacks_if_mapping_unreferenced,
|
||||
uintptr_t principal_mapping_address,
|
||||
bool sanitize_stacks) {
|
||||
const AppMemoryList& appmem) {
|
||||
return WriteMinidumpImpl(minidump_path, -1, -1, crashing_process,
|
||||
blob, blob_size,
|
||||
mappings, appmem,
|
||||
skip_stacks_if_mapping_unreferenced,
|
||||
principal_mapping_address,
|
||||
sanitize_stacks);
|
||||
mappings, appmem);
|
||||
}
|
||||
|
||||
bool WriteMinidump(int minidump_fd, pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
const AppMemoryList& appmem,
|
||||
bool skip_stacks_if_mapping_unreferenced,
|
||||
uintptr_t principal_mapping_address,
|
||||
bool sanitize_stacks) {
|
||||
const AppMemoryList& appmem) {
|
||||
return WriteMinidumpImpl(NULL, minidump_fd, -1, crashing_process,
|
||||
blob, blob_size,
|
||||
mappings, appmem,
|
||||
skip_stacks_if_mapping_unreferenced,
|
||||
principal_mapping_address,
|
||||
sanitize_stacks);
|
||||
mappings, appmem);
|
||||
}
|
||||
|
||||
bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit,
|
||||
pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
const AppMemoryList& appmem,
|
||||
bool skip_stacks_if_mapping_unreferenced,
|
||||
uintptr_t principal_mapping_address,
|
||||
bool sanitize_stacks) {
|
||||
const AppMemoryList& appmem) {
|
||||
return WriteMinidumpImpl(minidump_path, -1, minidump_size_limit,
|
||||
crashing_process, blob, blob_size,
|
||||
mappings, appmem,
|
||||
skip_stacks_if_mapping_unreferenced,
|
||||
principal_mapping_address,
|
||||
sanitize_stacks);
|
||||
mappings, appmem);
|
||||
}
|
||||
|
||||
bool WriteMinidump(int minidump_fd, off_t minidump_size_limit,
|
||||
pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
const AppMemoryList& appmem,
|
||||
bool skip_stacks_if_mapping_unreferenced,
|
||||
uintptr_t principal_mapping_address,
|
||||
bool sanitize_stacks) {
|
||||
const AppMemoryList& appmem) {
|
||||
return WriteMinidumpImpl(NULL, minidump_fd, minidump_size_limit,
|
||||
crashing_process, blob, blob_size,
|
||||
mappings, appmem,
|
||||
skip_stacks_if_mapping_unreferenced,
|
||||
principal_mapping_address,
|
||||
sanitize_stacks);
|
||||
mappings, appmem);
|
||||
}
|
||||
|
||||
bool WriteMinidump(const char* filename,
|
||||
const MappingList& mappings,
|
||||
const AppMemoryList& appmem,
|
||||
LinuxDumper* dumper) {
|
||||
MinidumpWriter writer(filename, -1, NULL, mappings, appmem,
|
||||
false, 0, false, dumper);
|
||||
MinidumpWriter writer(filename, -1, NULL, mappings, appmem, dumper);
|
||||
if (!writer.Init())
|
||||
return false;
|
||||
return writer.Dump();
|
||||
|
|
|
@ -78,16 +78,10 @@ typedef std::list<AppMemory> AppMemoryList;
|
|||
//
|
||||
// Returns true iff successful.
|
||||
bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
bool skip_stacks_if_mapping_unreferenced = false,
|
||||
uintptr_t principal_mapping_address = 0,
|
||||
bool sanitize_stacks = false);
|
||||
const void* blob, size_t blob_size);
|
||||
// Same as above but takes an open file descriptor instead of a path.
|
||||
bool WriteMinidump(int minidump_fd, pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
bool skip_stacks_if_mapping_unreferenced = false,
|
||||
uintptr_t principal_mapping_address = 0,
|
||||
bool sanitize_stacks = false);
|
||||
const void* blob, size_t blob_size);
|
||||
|
||||
// Alternate form of WriteMinidump() that works with processes that
|
||||
// are not expected to have crashed. If |process_blamed_thread| is
|
||||
|
@ -102,35 +96,23 @@ bool WriteMinidump(const char* minidump_path, pid_t process,
|
|||
bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
const AppMemoryList& appdata,
|
||||
bool skip_stacks_if_mapping_unreferenced = false,
|
||||
uintptr_t principal_mapping_address = 0,
|
||||
bool sanitize_stacks = false);
|
||||
const AppMemoryList& appdata);
|
||||
bool WriteMinidump(int minidump_fd, pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
const AppMemoryList& appdata,
|
||||
bool skip_stacks_if_mapping_unreferenced = false,
|
||||
uintptr_t principal_mapping_address = 0,
|
||||
bool sanitize_stacks = false);
|
||||
const AppMemoryList& appdata);
|
||||
|
||||
// These overloads also allow passing a file size limit for the minidump.
|
||||
bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit,
|
||||
pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
const AppMemoryList& appdata,
|
||||
bool skip_stacks_if_mapping_unreferenced = false,
|
||||
uintptr_t principal_mapping_address = 0,
|
||||
bool sanitize_stacks = false);
|
||||
const AppMemoryList& appdata);
|
||||
bool WriteMinidump(int minidump_fd, off_t minidump_size_limit,
|
||||
pid_t crashing_process,
|
||||
const void* blob, size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
const AppMemoryList& appdata,
|
||||
bool skip_stacks_if_mapping_unreferenced = false,
|
||||
uintptr_t principal_mapping_address = 0,
|
||||
bool sanitize_stacks = false);
|
||||
const AppMemoryList& appdata);
|
||||
|
||||
bool WriteMinidump(const char* filename,
|
||||
const MappingList& mappings,
|
||||
|
|
|
@ -70,7 +70,7 @@ TEST(MinidumpWriterTest, SetupWithPath) {
|
|||
char b;
|
||||
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit_group);
|
||||
syscall(__NR_exit);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
|
@ -87,7 +87,6 @@ TEST(MinidumpWriterTest, SetupWithPath) {
|
|||
ASSERT_GT(st.st_size, 0);
|
||||
|
||||
close(fds[1]);
|
||||
IGNORE_EINTR(waitpid(child, nullptr, 0));
|
||||
}
|
||||
|
||||
TEST(MinidumpWriterTest, SetupWithFD) {
|
||||
|
@ -100,7 +99,7 @@ TEST(MinidumpWriterTest, SetupWithFD) {
|
|||
char b;
|
||||
HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit_group);
|
||||
syscall(__NR_exit);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
|
@ -118,7 +117,6 @@ TEST(MinidumpWriterTest, SetupWithFD) {
|
|||
ASSERT_GT(st.st_size, 0);
|
||||
|
||||
close(fds[1]);
|
||||
IGNORE_EINTR(waitpid(child, nullptr, 0));
|
||||
}
|
||||
|
||||
// Test that mapping info can be specified when writing a minidump,
|
||||
|
@ -154,7 +152,7 @@ TEST(MinidumpWriterTest, MappingInfo) {
|
|||
char b;
|
||||
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit_group);
|
||||
syscall(__NR_exit);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
|
@ -181,7 +179,7 @@ TEST(MinidumpWriterTest, MappingInfo) {
|
|||
memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
|
||||
mappings.push_back(mapping);
|
||||
ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
|
||||
mappings, memory_list, false, 0, false));
|
||||
mappings, memory_list));
|
||||
|
||||
// Read the minidump. Load the module list, and ensure that
|
||||
// the mmap'ed |memory| is listed with the given module name
|
||||
|
@ -215,150 +213,6 @@ TEST(MinidumpWriterTest, MappingInfo) {
|
|||
EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_DSO_DEBUG, &len));
|
||||
|
||||
close(fds[1]);
|
||||
IGNORE_EINTR(waitpid(child, nullptr, 0));
|
||||
}
|
||||
|
||||
// Test that minidumping is skipped while writing minidumps if principal mapping
|
||||
// is not referenced.
|
||||
TEST(MinidumpWriterTest, MinidumpSkippedIfRequested) {
|
||||
int fds[2];
|
||||
ASSERT_NE(-1, pipe(fds));
|
||||
|
||||
const pid_t child = fork();
|
||||
if (child == 0) {
|
||||
close(fds[1]);
|
||||
char b;
|
||||
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit_group);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
ExceptionHandler::CrashContext context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
ASSERT_EQ(0, getcontext(&context.context));
|
||||
context.tid = child;
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string templ = temp_dir.path() + kMDWriterUnitTestFileName;
|
||||
|
||||
// pass an invalid principal mapping address, which will force
|
||||
// WriteMinidump to not write a minidump.
|
||||
ASSERT_FALSE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
|
||||
true, static_cast<uintptr_t>(0x0102030405060708ull),
|
||||
false));
|
||||
close(fds[1]);
|
||||
IGNORE_EINTR(waitpid(child, nullptr, 0));
|
||||
}
|
||||
|
||||
// Test that minidumping is skipped while writing minidumps if principal mapping
|
||||
// is not referenced.
|
||||
TEST(MinidumpWriterTest, MinidumpStacksSkippedIfRequested) {
|
||||
int fds[2];
|
||||
ASSERT_NE(-1, pipe(fds));
|
||||
|
||||
const pid_t child = fork();
|
||||
if (child == 0) {
|
||||
close(fds[1]);
|
||||
|
||||
// Create a thread that does not return, and only references libc (not the
|
||||
// current executable). This thread should not be captured in the minidump.
|
||||
pthread_t thread;
|
||||
pthread_attr_t thread_attributes;
|
||||
pthread_attr_init(&thread_attributes);
|
||||
pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED);
|
||||
sigset_t sigset;
|
||||
sigemptyset(&sigset);
|
||||
pthread_create(&thread, &thread_attributes,
|
||||
reinterpret_cast<void* (*)(void*)>(&sigsuspend), &sigset);
|
||||
|
||||
char b;
|
||||
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit_group);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
ExceptionHandler::CrashContext context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
ASSERT_EQ(0, getcontext(&context.context));
|
||||
context.tid = child;
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string templ = temp_dir.path() + kMDWriterUnitTestFileName;
|
||||
|
||||
// Pass an invalid principal mapping address, which will force
|
||||
// WriteMinidump to not dump any thread stacks.
|
||||
ASSERT_TRUE(WriteMinidump(
|
||||
templ.c_str(), child, &context, sizeof(context), true,
|
||||
reinterpret_cast<uintptr_t>(google_breakpad::WriteFile), false));
|
||||
|
||||
// Read the minidump. And ensure that thread memory was dumped only for the
|
||||
// main thread.
|
||||
Minidump minidump(templ);
|
||||
ASSERT_TRUE(minidump.Read());
|
||||
|
||||
MinidumpThreadList *threads = minidump.GetThreadList();
|
||||
int threads_with_stacks = 0;
|
||||
for (unsigned int i = 0; i < threads->thread_count(); ++i) {
|
||||
MinidumpThread *thread = threads->GetThreadAtIndex(i);
|
||||
if (thread->GetMemory()) {
|
||||
++threads_with_stacks;
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(1, threads_with_stacks);
|
||||
close(fds[1]);
|
||||
IGNORE_EINTR(waitpid(child, nullptr, 0));
|
||||
}
|
||||
|
||||
// Test that stacks can be sanitized while writing minidumps.
|
||||
TEST(MinidumpWriterTest, StacksAreSanitizedIfRequested) {
|
||||
int fds[2];
|
||||
ASSERT_NE(-1, pipe(fds));
|
||||
|
||||
const pid_t child = fork();
|
||||
if (child == 0) {
|
||||
close(fds[1]);
|
||||
char b;
|
||||
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit_group);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
ExceptionHandler::CrashContext context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
ASSERT_EQ(0, getcontext(&context.context));
|
||||
context.tid = child;
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string templ = temp_dir.path() + kMDWriterUnitTestFileName;
|
||||
// pass an invalid principal mapping address, which will force
|
||||
// WriteMinidump to not dump any thread stacks.
|
||||
ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
|
||||
false, 0, true));
|
||||
|
||||
// Read the minidump. And ensure that thread memory contains a defaced value.
|
||||
Minidump minidump(templ);
|
||||
ASSERT_TRUE(minidump.Read());
|
||||
|
||||
const uintptr_t defaced =
|
||||
#if defined(__LP64__)
|
||||
0x0defaced0defaced;
|
||||
#else
|
||||
0x0defaced;
|
||||
#endif
|
||||
MinidumpThreadList *threads = minidump.GetThreadList();
|
||||
for (unsigned int i = 0; i < threads->thread_count(); ++i) {
|
||||
MinidumpThread *thread = threads->GetThreadAtIndex(i);
|
||||
MinidumpMemoryRegion *mem = thread->GetMemory();
|
||||
ASSERT_TRUE(mem != nullptr);
|
||||
uint32_t sz = mem->GetSize();
|
||||
const uint8_t *data = mem->GetMemory();
|
||||
ASSERT_TRUE(memmem(data, sz, &defaced, sizeof(defaced)) != nullptr);
|
||||
}
|
||||
close(fds[1]);
|
||||
IGNORE_EINTR(waitpid(child, nullptr, 0));
|
||||
}
|
||||
|
||||
// Test that a binary with a longer-than-usual build id note
|
||||
|
@ -375,7 +229,7 @@ TEST(MinidumpWriterTest, BuildIDLong) {
|
|||
char b;
|
||||
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit_group);
|
||||
syscall(__NR_exit);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
|
@ -406,8 +260,6 @@ TEST(MinidumpWriterTest, BuildIDLong) {
|
|||
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
|
||||
EXPECT_EQ(module_identifier, module->debug_identifier());
|
||||
EXPECT_EQ(build_id, module->code_identifier());
|
||||
|
||||
IGNORE_EINTR(waitpid(child, nullptr, 0));
|
||||
}
|
||||
|
||||
// Test that mapping info can be specified, and that it overrides
|
||||
|
@ -456,7 +308,7 @@ TEST(MinidumpWriterTest, MappingInfoContained) {
|
|||
char b;
|
||||
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit_group);
|
||||
syscall(__NR_exit);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
|
@ -502,7 +354,6 @@ TEST(MinidumpWriterTest, MappingInfoContained) {
|
|||
EXPECT_EQ(module_identifier, module->debug_identifier());
|
||||
|
||||
close(fds[1]);
|
||||
IGNORE_EINTR(waitpid(child, nullptr, 0));
|
||||
}
|
||||
|
||||
TEST(MinidumpWriterTest, DeletedBinary) {
|
||||
|
@ -594,8 +445,6 @@ TEST(MinidumpWriterTest, DeletedBinary) {
|
|||
// which is always zero on Linux.
|
||||
module_identifier += "0";
|
||||
EXPECT_EQ(module_identifier, module->debug_identifier());
|
||||
|
||||
IGNORE_EINTR(waitpid(child_pid, nullptr, 0));
|
||||
}
|
||||
|
||||
// Test that an additional memory region can be added to the minidump.
|
||||
|
@ -623,7 +472,7 @@ TEST(MinidumpWriterTest, AdditionalMemory) {
|
|||
char b;
|
||||
HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit_group);
|
||||
syscall(__NR_exit);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
|
@ -668,7 +517,6 @@ TEST(MinidumpWriterTest, AdditionalMemory) {
|
|||
|
||||
delete[] memory;
|
||||
close(fds[1]);
|
||||
IGNORE_EINTR(waitpid(child, nullptr, 0));
|
||||
}
|
||||
|
||||
// Test that an invalid thread stack pointer still results in a minidump.
|
||||
|
@ -682,7 +530,7 @@ TEST(MinidumpWriterTest, InvalidStackPointer) {
|
|||
char b;
|
||||
HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit_group);
|
||||
syscall(__NR_exit);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
|
@ -748,7 +596,6 @@ TEST(MinidumpWriterTest, InvalidStackPointer) {
|
|||
#endif
|
||||
|
||||
close(fds[1]);
|
||||
IGNORE_EINTR(waitpid(child, nullptr, 0));
|
||||
}
|
||||
|
||||
// Test that limiting the size of the minidump works.
|
||||
|
@ -923,7 +770,6 @@ TEST(MinidumpWriterTest, MinidumpSizeLimit) {
|
|||
|
||||
// Kill the helper program.
|
||||
kill(child_pid, SIGKILL);
|
||||
IGNORE_EINTR(waitpid(child_pid, nullptr, 0));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
// nlist function implemented to work on 64-bit.
|
||||
|
||||
#ifndef CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__
|
||||
#define CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__
|
||||
|
||||
#include <mach/machine.h>
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ extern "C" {
|
|||
mach_msg_header_t* reply);
|
||||
|
||||
// This symbol must be visible to dlsym() - see
|
||||
// https://bugs.chromium.org/p/google-breakpad/issues/detail?id=345 for details.
|
||||
// http://code.google.com/p/google-breakpad/issues/detail?id=345 for details.
|
||||
kern_return_t catch_exception_raise(mach_port_t target_port,
|
||||
mach_port_t failed_thread,
|
||||
mach_port_t task,
|
||||
|
@ -356,11 +356,6 @@ bool ExceptionHandler::WriteMinidumpWithException(
|
|||
bool report_current_thread) {
|
||||
bool result = false;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
// _exit() should never be called on iOS.
|
||||
exit_after_write = false;
|
||||
#endif
|
||||
|
||||
if (directCallback_) {
|
||||
if (directCallback_(callback_context_,
|
||||
exception_type,
|
||||
|
@ -464,7 +459,7 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
|
|||
|
||||
kern_return_t result;
|
||||
// TODO: Handle the case where |target_behavior| has MACH_EXCEPTION_CODES
|
||||
// set. https://bugs.chromium.org/p/google-breakpad/issues/detail?id=551
|
||||
// set. https://code.google.com/p/google-breakpad/issues/detail?id=551
|
||||
switch (target_behavior) {
|
||||
case EXCEPTION_DEFAULT:
|
||||
result = exception_raise(target_port, failed_thread, task, exception,
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
F93A887F0E8B4C8C0026AF89 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FE0BEF947200920385 /* macho_utilities.cc */; };
|
||||
F93A88800E8B4C8C0026AF89 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FA0BEF947200920385 /* file_id.cc */; };
|
||||
F93A88860E8B4C9A0026AF89 /* dwarftests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9721F310E8B07E800D7E813 /* dwarftests.mm */; };
|
||||
F93A88870E8B4C9A0026AF89 /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F390E8B0D0D00D7E813 /* dump_syms.cc */; };
|
||||
F93A88870E8B4C9A0026AF89 /* dump_syms.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9721F390E8B0D0D00D7E813 /* dump_syms.mm */; };
|
||||
F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F760E8B0DC700D7E813 /* bytereader.cc */; };
|
||||
F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */; };
|
||||
F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F780E8B0DC700D7E813 /* functioninfo.cc */; };
|
||||
|
@ -151,7 +151,7 @@
|
|||
F9721F300E8B07E800D7E813 /* dwarftests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dwarftests.h; sourceTree = "<group>"; };
|
||||
F9721F310E8B07E800D7E813 /* dwarftests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = dwarftests.mm; sourceTree = "<group>"; };
|
||||
F9721F380E8B0CFC00D7E813 /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = SOURCE_ROOT; };
|
||||
F9721F390E8B0D0D00D7E813 /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = SOURCE_ROOT; };
|
||||
F9721F390E8B0D0D00D7E813 /* dump_syms.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.mm; path = ../../../common/mac/dump_syms.mm; sourceTree = SOURCE_ROOT; };
|
||||
F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
F9721F760E8B0DC700D7E813 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; };
|
||||
F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -240,7 +240,7 @@
|
|||
F9721F760E8B0DC700D7E813 /* bytereader.cc */,
|
||||
F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */,
|
||||
F9721F780E8B0DC700D7E813 /* functioninfo.cc */,
|
||||
F9721F390E8B0D0D00D7E813 /* dump_syms.cc */,
|
||||
F9721F390E8B0D0D00D7E813 /* dump_syms.mm */,
|
||||
F9721F380E8B0CFC00D7E813 /* dump_syms.h */,
|
||||
F917C4F70E03265A00F86017 /* breakpad_exc_server.c */,
|
||||
F917C4F80E03265A00F86017 /* breakpad_exc_server.h */,
|
||||
|
@ -597,7 +597,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F93A88860E8B4C9A0026AF89 /* dwarftests.mm in Sources */,
|
||||
F93A88870E8B4C9A0026AF89 /* dump_syms.cc in Sources */,
|
||||
F93A88870E8B4C9A0026AF89 /* dump_syms.mm in Sources */,
|
||||
F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */,
|
||||
F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */,
|
||||
F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */,
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "client/mac/handler/exception_handler.h"
|
||||
#include "common/linux/ignore_ret.h"
|
||||
#include "common/mac/MachIPC.h"
|
||||
#include "common/tests/auto_tempdir.h"
|
||||
#include "google_breakpad/processor/minidump.h"
|
||||
|
@ -94,7 +93,7 @@ static bool MDCallback(const char *dump_dir, const char *file_name,
|
|||
path.append(".dmp");
|
||||
|
||||
int fd = *reinterpret_cast<int*>(context);
|
||||
IGNORE_RET(write(fd, path.c_str(), path.length() + 1));
|
||||
(void)write(fd, path.c_str(), path.length() + 1);
|
||||
close(fd);
|
||||
exit(0);
|
||||
// not reached
|
||||
|
@ -294,7 +293,7 @@ TEST_F(ExceptionHandlerTest, DumpChildProcess) {
|
|||
|
||||
// Unblock child process
|
||||
uint8_t data = 1;
|
||||
IGNORE_RET(write(fds[1], &data, 1));
|
||||
(void)write(fds[1], &data, 1);
|
||||
|
||||
// Child process should have exited with a zero status.
|
||||
int ret;
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
#include "breakpad_googletest_includes.h"
|
||||
#include "client/mac/handler/minidump_generator.h"
|
||||
#include "client/mac/tests/spawn_child_process.h"
|
||||
#include "common/linux/ignore_ret.h"
|
||||
#include "common/mac/MachIPC.h"
|
||||
#include "common/tests/auto_tempdir.h"
|
||||
#include "google_breakpad/processor/minidump.h"
|
||||
|
@ -191,7 +190,7 @@ TEST_F(MinidumpGeneratorTest, OutOfProcess) {
|
|||
|
||||
// Unblock child process
|
||||
uint8_t data = 1;
|
||||
IGNORE_RET(write(fds[1], &data, 1));
|
||||
(void)write(fds[1], &data, 1);
|
||||
|
||||
// Child process should have exited with a zero status.
|
||||
int ret;
|
||||
|
|
|
@ -968,20 +968,9 @@ bool CrashGenerationServer::GenerateDump(const ClientInfo& client,
|
|||
dump_generator.SetCallback(&callback);
|
||||
}
|
||||
|
||||
if (!dump_generator.GenerateDumpFile(dump_path)) {
|
||||
if (!dump_generator.GenerateDumpFile(dump_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the client requests a full memory dump, we will write a normal mini
|
||||
// dump and a full memory dump. Both dump files use the same uuid as file
|
||||
// name prefix.
|
||||
if (client.dump_type() & MiniDumpWithFullMemory) {
|
||||
std::wstring full_dump_path;
|
||||
if (!dump_generator.GenerateFullDumpFile(&full_dump_path)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return dump_generator.WriteMinidump();
|
||||
}
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ bool HandleTraceData::CollectHandleData(
|
|||
stream_data->Reserved = 0;
|
||||
std::copy(operations_.begin(),
|
||||
operations_.end(),
|
||||
#if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER)
|
||||
#ifdef _MSC_VER
|
||||
stdext::checked_array_iterator<AVRF_HANDLE_OPERATION*>(
|
||||
reinterpret_cast<AVRF_HANDLE_OPERATION*>(stream_data + 1),
|
||||
operations_.size())
|
||||
|
@ -271,14 +271,12 @@ MinidumpGenerator::MinidumpGenerator(
|
|||
dump_type_(dump_type),
|
||||
is_client_pointers_(is_client_pointers),
|
||||
dump_path_(dump_path),
|
||||
uuid_generated_(false),
|
||||
dump_file_(INVALID_HANDLE_VALUE),
|
||||
full_dump_file_(INVALID_HANDLE_VALUE),
|
||||
dump_file_is_internal_(false),
|
||||
full_dump_file_is_internal_(false),
|
||||
additional_streams_(NULL),
|
||||
callback_info_(NULL) {
|
||||
uuid_ = {0};
|
||||
InitializeCriticalSection(&module_load_sync_);
|
||||
InitializeCriticalSection(&get_proc_address_sync_);
|
||||
}
|
||||
|
@ -564,17 +562,15 @@ MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
|
|||
}
|
||||
|
||||
bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
|
||||
if (!uuid_generated_) {
|
||||
UuidCreateType create_uuid = GetCreateUuid();
|
||||
if (!create_uuid) {
|
||||
return false;
|
||||
}
|
||||
UUID id = {0};
|
||||
|
||||
create_uuid(&uuid_);
|
||||
uuid_generated_ = true;
|
||||
UuidCreateType create_uuid = GetCreateUuid();
|
||||
if (!create_uuid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wstring id_str = GUIDString::GUIDToWString(&uuid_);
|
||||
create_uuid(&id);
|
||||
wstring id_str = GUIDString::GUIDToWString(&id);
|
||||
|
||||
*file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
|
||||
return true;
|
||||
|
|
|
@ -168,10 +168,6 @@ class MinidumpGenerator {
|
|||
// Folder path to store dump files.
|
||||
std::wstring dump_path_;
|
||||
|
||||
// UUID used to make dump file names.
|
||||
UUID uuid_;
|
||||
bool uuid_generated_;
|
||||
|
||||
// The file where the dump will be written.
|
||||
HANDLE dump_file_;
|
||||
|
||||
|
|
|
@ -41,11 +41,6 @@
|
|||
|
||||
namespace google_breakpad {
|
||||
|
||||
// This define is new to Windows 10.
|
||||
#ifndef DBG_PRINTEXCEPTION_WIDE_C
|
||||
#define DBG_PRINTEXCEPTION_WIDE_C ((DWORD)0x4001000A)
|
||||
#endif
|
||||
|
||||
vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
|
||||
LONG ExceptionHandler::handler_stack_index_ = 0;
|
||||
CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_;
|
||||
|
@ -478,9 +473,7 @@ LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) {
|
|||
DWORD code = exinfo->ExceptionRecord->ExceptionCode;
|
||||
LONG action;
|
||||
bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) ||
|
||||
(code == EXCEPTION_SINGLE_STEP) ||
|
||||
(code == DBG_PRINTEXCEPTION_C) ||
|
||||
(code == DBG_PRINTEXCEPTION_WIDE_C);
|
||||
(code == EXCEPTION_SINGLE_STEP);
|
||||
|
||||
if (code == EXCEPTION_INVALID_HANDLE &&
|
||||
current_handler->consume_invalid_handle_exceptions_) {
|
||||
|
|
|
@ -28,7 +28,9 @@
|
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "testing/include/gmock/gmock.h"
|
||||
|
||||
#include "client/windows/crash_generation/crash_generation_server.h"
|
||||
#include "client/windows/common/ipc_protocol.h"
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
#include <objbase.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "client/windows/unittests/dump_analysis.h" // NOLINT
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
DumpAnalysis::~DumpAnalysis() {
|
||||
if (dump_file_view_ != NULL) {
|
||||
|
|
|
@ -82,7 +82,7 @@ void ExceptionHandlerDeathTest::SetUp() {
|
|||
// The test case name is exposed as a c-style string,
|
||||
// convert it to a wchar_t string.
|
||||
int dwRet = MultiByteToWideChar(CP_ACP, 0, test_info->name(),
|
||||
static_cast<int>(strlen(test_info->name())),
|
||||
strlen(test_info->name()),
|
||||
test_name_wide,
|
||||
MAX_PATH);
|
||||
if (!dwRet) {
|
||||
|
@ -293,8 +293,8 @@ wstring find_minidump_in_directory(const wstring &directory) {
|
|||
wstring filename;
|
||||
do {
|
||||
const wchar_t extension[] = L".dmp";
|
||||
const size_t extension_length = sizeof(extension) / sizeof(extension[0]) - 1;
|
||||
const size_t filename_length = wcslen(find_data.cFileName);
|
||||
const int extension_length = sizeof(extension) / sizeof(extension[0]) - 1;
|
||||
const int filename_length = wcslen(find_data.cFileName);
|
||||
if (filename_length > extension_length &&
|
||||
wcsncmp(extension,
|
||||
find_data.cFileName + filename_length - extension_length,
|
||||
|
@ -357,8 +357,8 @@ TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemory) {
|
|||
|
||||
// Read the minidump. Locate the exception record and the
|
||||
// memory list, and then ensure that there is a memory region
|
||||
// in the memory list that covers at least 128 bytes on either
|
||||
// side of the instruction pointer from the exception record.
|
||||
// in the memory list that covers the instruction pointer from
|
||||
// the exception record.
|
||||
{
|
||||
Minidump minidump(minidump_filename);
|
||||
ASSERT_TRUE(minidump.Read());
|
||||
|
@ -379,23 +379,18 @@ TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemory) {
|
|||
memory_list->GetMemoryRegionForAddress(instruction_pointer);
|
||||
ASSERT_TRUE(region);
|
||||
|
||||
EXPECT_LE(kMemorySize, region->GetSize());
|
||||
EXPECT_EQ(kMemorySize, region->GetSize());
|
||||
const uint8_t* bytes = region->GetMemory();
|
||||
ASSERT_TRUE(bytes);
|
||||
|
||||
uint64_t ip_offset = instruction_pointer - region->GetBase();
|
||||
EXPECT_GE(region->GetSize() - kOffset, ip_offset);
|
||||
EXPECT_LE(kOffset, ip_offset);
|
||||
|
||||
uint8_t prefix_bytes[kOffset];
|
||||
uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(instructions)];
|
||||
memset(prefix_bytes, 0, sizeof(prefix_bytes));
|
||||
memset(suffix_bytes, 0, sizeof(suffix_bytes));
|
||||
EXPECT_EQ(0, memcmp(bytes + ip_offset - kOffset, prefix_bytes,
|
||||
sizeof(prefix_bytes)));
|
||||
EXPECT_EQ(0, memcmp(bytes + ip_offset, instructions, sizeof(instructions)));
|
||||
EXPECT_EQ(0, memcmp(bytes + ip_offset + sizeof(instructions), suffix_bytes,
|
||||
sizeof(suffix_bytes)));
|
||||
EXPECT_EQ(0, memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)));
|
||||
EXPECT_EQ(0, memcmp(bytes + kOffset, instructions, sizeof(instructions)));
|
||||
EXPECT_EQ(0, memcmp(bytes + kOffset + sizeof(instructions),
|
||||
suffix_bytes, sizeof(suffix_bytes)));
|
||||
}
|
||||
|
||||
DeleteFileW(minidump_filename_wide.c_str());
|
||||
|
|
|
@ -120,7 +120,7 @@ void ExceptionHandlerTest::SetUp() {
|
|||
// THe test case name is exposed to use as a c-style string,
|
||||
// But we might be working in UNICODE here on Windows.
|
||||
int dwRet = MultiByteToWideChar(CP_ACP, 0, test_info->name(),
|
||||
static_cast<int>(strlen(test_info->name())),
|
||||
strlen(test_info->name()),
|
||||
test_name_wide,
|
||||
MAX_PATH);
|
||||
if (!dwRet) {
|
||||
|
@ -247,7 +247,6 @@ TEST_F(ExceptionHandlerTest, InvalidParameterMiniDumpTest) {
|
|||
EXPECT_EXIT(DoCrashInvalidParameter(), ::testing::ExitedWithCode(0), "");
|
||||
ASSERT_TRUE(!dump_file.empty() && !full_dump_file.empty());
|
||||
ASSERT_TRUE(DoesPathExist(dump_file.c_str()));
|
||||
ASSERT_TRUE(DoesPathExist(full_dump_file.c_str()));
|
||||
|
||||
// Verify the dump for infos.
|
||||
DumpAnalysis mini(dump_file);
|
||||
|
@ -319,7 +318,6 @@ TEST_F(ExceptionHandlerTest, PureVirtualCallMiniDumpTest) {
|
|||
EXPECT_EXIT(DoCrashPureVirtualCall(), ::testing::ExitedWithCode(0), "");
|
||||
ASSERT_TRUE(!dump_file.empty() && !full_dump_file.empty());
|
||||
ASSERT_TRUE(DoesPathExist(dump_file.c_str()));
|
||||
ASSERT_TRUE(DoesPathExist(full_dump_file.c_str()));
|
||||
|
||||
// Verify the dump for infos.
|
||||
DumpAnalysis mini(dump_file);
|
||||
|
|
|
@ -31,10 +31,11 @@
|
|||
#include <objbase.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "client/windows/crash_generation/minidump_generator.h"
|
||||
#include "client/windows/unittests/dump_analysis.h" // NOLINT
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Minidump with stacks, PEB, TEB, and unloaded module list.
|
||||
|
@ -93,7 +94,7 @@ class MinidumpTest: public testing::Test {
|
|||
STATUS_ACCESS_VIOLATION, // ExceptionCode
|
||||
0, // ExceptionFlags
|
||||
NULL, // ExceptionRecord;
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(0xCAFEBABE)), // ExceptionAddress;
|
||||
reinterpret_cast<void*>(0xCAFEBABE), // ExceptionAddress;
|
||||
2, // NumberParameters;
|
||||
{ EXCEPTION_WRITE_FAULT, reinterpret_cast<ULONG_PTR>(this) }
|
||||
};
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Ignore other VCSs.
|
||||
.repo/
|
||||
.svn/
|
||||
|
||||
# Ignore common compiled artifacts.
|
||||
|
@ -48,12 +47,6 @@ lib*.a
|
|||
/src/tools/linux/symupload/minidump_upload
|
||||
/src/tools/linux/symupload/sym_upload
|
||||
/src/tools/mac/dump_syms/dump_syms
|
||||
/src/tools/mac/dump_syms/dump_syms_mac
|
||||
|
||||
# Ignore unit test artifacts.
|
||||
*_unittest
|
||||
*.log
|
||||
*.trs
|
||||
|
||||
# Ignore autotools generated artifacts.
|
||||
.deps
|
||||
|
@ -84,6 +77,7 @@ src/Makefile
|
|||
|
||||
# Ignore directories gclient syncs.
|
||||
src/testing
|
||||
src/third_party/glog
|
||||
src/third_party/lss
|
||||
src/third_party/protobuf
|
||||
src/tools/gyp
|
||||
|
|
|
@ -33,10 +33,18 @@
|
|||
# 'gclient runhooks' rather than 'gclient sync'.
|
||||
|
||||
deps = {
|
||||
# Logging code.
|
||||
"src/src/third_party/glog":
|
||||
"https://github.com/google/glog.git" +
|
||||
"@v0.3.4",
|
||||
|
||||
# Testing libraries and utilities.
|
||||
"src/src/testing":
|
||||
"https://github.com/google/googlemock.git" +
|
||||
"@release-1.7.0",
|
||||
"src/src/testing/gtest":
|
||||
"https://github.com/google/googletest.git" +
|
||||
"@release-1.8.0",
|
||||
"@release-1.7.0",
|
||||
|
||||
# Protobuf.
|
||||
"src/src/third_party/protobuf/protobuf":
|
||||
|
@ -46,39 +54,22 @@ deps = {
|
|||
# GYP project generator.
|
||||
"src/src/tools/gyp":
|
||||
"https://chromium.googlesource.com/external/gyp/" +
|
||||
"@324dd166b7c0b39d513026fa52d6280ac6d56770",
|
||||
"@e8ab0833a42691cd2184bd4c45d779e43821d3e0",
|
||||
|
||||
# Linux syscall support.
|
||||
"src/src/third_party/lss":
|
||||
"https://chromium.googlesource.com/linux-syscall-support/" +
|
||||
"@e6527b0cd469e3ff5764785dadcb39bf7d787154",
|
||||
"@3f6478ac95edf86cd3da300c2c0d34a438f5dbeb",
|
||||
}
|
||||
|
||||
hooks = [
|
||||
{
|
||||
# Keep the manifest up to date.
|
||||
"action": ["python", "src/src/tools/python/deps-to-manifest.py",
|
||||
"src/DEPS", "src/default.xml"],
|
||||
# TODO(chrisha): Fix the GYP files so that they work without
|
||||
# --no-circular-check.
|
||||
"pattern": ".",
|
||||
"action": ["python",
|
||||
"src/src/tools/gyp/gyp_main.py",
|
||||
"--no-circular-check",
|
||||
"src/src/client/windows/breakpad_client.gyp"],
|
||||
},
|
||||
]
|
||||
|
||||
hooks_os = {
|
||||
'win': [
|
||||
{
|
||||
# TODO(chrisha): Fix the GYP files so that they work without
|
||||
# --no-circular-check.
|
||||
"pattern": ".",
|
||||
"action": ["python",
|
||||
"src/src/tools/gyp/gyp_main.py",
|
||||
"--no-circular-check",
|
||||
"src/src/client/windows/breakpad_client.gyp"],
|
||||
},
|
||||
{
|
||||
# XXX: this and above should all be wired into build/all.gyp ?
|
||||
"action": ["python",
|
||||
"src/src/tools/gyp/gyp_main.py",
|
||||
"--no-circular-check",
|
||||
"src/src/tools/windows/tools_windows.gyp"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
69c2c51dd89965d234eec16e3a9353634831916b
|
||||
704f41ec901c419f8c321742114b415e6f5ceacc
|
||||
|
|
|
@ -43,7 +43,17 @@ AM_CXXFLAGS += -I$(top_srcdir)/src/common/android/include
|
|||
AM_CXXFLAGS += -I$(top_srcdir)/src/common/android/testing/include
|
||||
endif
|
||||
|
||||
AM_CXXFLAGS += $(WARN_CXXFLAGS)
|
||||
if GCC
|
||||
# These are good warnings to be treated as errors
|
||||
AM_CXXFLAGS += \
|
||||
-Werror=missing-braces \
|
||||
-Werror=non-virtual-dtor \
|
||||
-Werror=overloaded-virtual \
|
||||
-Werror=reorder \
|
||||
-Werror=sign-compare \
|
||||
-Werror=unused-variable \
|
||||
-Werror=vla
|
||||
endif
|
||||
|
||||
if LINUX_HOST
|
||||
# Build as PIC on Linux, for linux_client_unittest_shlib
|
||||
|
@ -110,10 +120,8 @@ TEST_DEPS =
|
|||
else
|
||||
TEST_CFLAGS = \
|
||||
-I$(top_srcdir)/src/testing/include \
|
||||
-I$(top_srcdir)/src/testing/googletest/include \
|
||||
-I$(top_srcdir)/src/testing/googletest \
|
||||
-I$(top_srcdir)/src/testing/googlemock/include \
|
||||
-I$(top_srcdir)/src/testing/googlemock \
|
||||
-I$(top_srcdir)/src/testing/gtest/include \
|
||||
-I$(top_srcdir)/src/testing/gtest \
|
||||
-I$(top_srcdir)/src/testing
|
||||
TEST_LIBS = src/testing/libtesting.a
|
||||
TEST_DEPS = $(TEST_LIBS)
|
||||
|
@ -133,9 +141,9 @@ check_LIBRARIES += src/testing/libtesting.a
|
|||
if !SYSTEM_TEST_LIBS
|
||||
src_testing_libtesting_a_SOURCES = \
|
||||
src/breakpad_googletest_includes.h \
|
||||
src/testing/googletest/src/gtest-all.cc \
|
||||
src/testing/googletest/src/gtest_main.cc \
|
||||
src/testing/googlemock/src/gmock-all.cc
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/gtest/src/gtest_main.cc \
|
||||
src/testing/src/gmock-all.cc
|
||||
src_testing_libtesting_a_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) $(TEST_CFLAGS)
|
||||
endif
|
||||
|
@ -406,8 +414,7 @@ CLEANFILES += \
|
|||
src/client/linux/linux_client_unittest_shlib
|
||||
|
||||
check_PROGRAMS += \
|
||||
src/client/linux/linux_client_unittest \
|
||||
src/common/linux/google_crashdump_uploader_test
|
||||
src/client/linux/linux_client_unittest
|
||||
|
||||
if !DISABLE_TOOLS
|
||||
check_PROGRAMS += \
|
||||
|
@ -446,12 +453,8 @@ if ANDROID_HOST
|
|||
LOG_DRIVER = $(top_srcdir)/android/test-driver
|
||||
else
|
||||
# The default Autotools test driver script.
|
||||
if TESTS_AS_ROOT
|
||||
LOG_DRIVER = $(top_srcdir)/autotools/root-test-driver $(top_srcdir)/autotools/test-driver
|
||||
else
|
||||
LOG_DRIVER = $(top_srcdir)/autotools/test-driver
|
||||
endif !TESTS_AS_ROOT
|
||||
endif !ANDROID_HOST
|
||||
endif
|
||||
|
||||
if LINUX_HOST
|
||||
src_client_linux_linux_dumper_unittest_helper_SOURCES = \
|
||||
|
@ -573,7 +576,6 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \
|
|||
src/common/dwarf_line_to_module.cc \
|
||||
src/common/language.cc \
|
||||
src/common/module.cc \
|
||||
src/common/path_helper.cc \
|
||||
src/common/stabs_reader.cc \
|
||||
src/common/stabs_to_module.cc \
|
||||
src/common/dwarf/bytereader.cc \
|
||||
|
@ -591,14 +593,9 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \
|
|||
src/common/linux/memory_mapped_file.cc \
|
||||
src/common/linux/safe_readlink.cc \
|
||||
src/tools/linux/dump_syms/dump_syms.cc
|
||||
src_tools_linux_dump_syms_dump_syms_CXXFLAGS = \
|
||||
$(RUST_DEMANGLE_CFLAGS)
|
||||
src_tools_linux_dump_syms_dump_syms_LDADD = \
|
||||
$(RUST_DEMANGLE_LIBS)
|
||||
|
||||
src_tools_linux_md2core_minidump_2_core_SOURCES = \
|
||||
src/common/linux/memory_mapped_file.cc \
|
||||
src/common/path_helper.cc \
|
||||
src/tools/linux/md2core/minidump-2-core.cc \
|
||||
src/tools/linux/md2core/minidump_memory_range.h
|
||||
|
||||
|
@ -622,7 +619,6 @@ src_tools_mac_dump_syms_dump_syms_mac_SOURCES = \
|
|||
src/common/language.cc \
|
||||
src/common/md5.cc \
|
||||
src/common/module.cc \
|
||||
src/common/path_helper.cc \
|
||||
src/common/stabs_reader.cc \
|
||||
src/common/stabs_to_module.cc \
|
||||
src/common/dwarf/bytereader.cc \
|
||||
|
@ -645,10 +641,7 @@ src_tools_mac_dump_syms_dump_syms_mac_SOURCES = \
|
|||
src/tools/mac/dump_syms/dump_syms_tool.cc
|
||||
src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS= \
|
||||
-I$(top_srcdir)/src/third_party/mac_headers \
|
||||
$(RUST_DEMANGLE_CFLAGS) \
|
||||
-DHAVE_MACH_O_NLIST_H
|
||||
src_tools_mac_dump_syms_dump_syms_mac_LDADD= \
|
||||
$(RUST_DEMANGLE_LIBS)
|
||||
|
||||
src_common_dumper_unittest_SOURCES = \
|
||||
src/common/byte_cursor_unittest.cc \
|
||||
|
@ -662,7 +655,6 @@ src_common_dumper_unittest_SOURCES = \
|
|||
src/common/memory_range_unittest.cc \
|
||||
src/common/module.cc \
|
||||
src/common/module_unittest.cc \
|
||||
src/common/path_helper.cc \
|
||||
src/common/stabs_reader.cc \
|
||||
src/common/stabs_reader_unittest.cc \
|
||||
src/common/stabs_to_module.cc \
|
||||
|
@ -706,11 +698,9 @@ src_common_dumper_unittest_SOURCES = \
|
|||
src/common/tests/file_utils.cc
|
||||
src_common_dumper_unittest_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) $(TEST_CFLAGS) \
|
||||
$(RUST_DEMANGLE_CFLAGS) \
|
||||
$(PTHREAD_CFLAGS)
|
||||
src_common_dumper_unittest_LDADD = \
|
||||
$(TEST_LIBS) \
|
||||
$(RUST_DEMANGLE_LIBS) \
|
||||
$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
|
||||
|
||||
src_common_mac_macho_reader_unittest_SOURCES = \
|
||||
|
@ -720,7 +710,6 @@ src_common_mac_macho_reader_unittest_SOURCES = \
|
|||
src/common/language.cc \
|
||||
src/common/md5.cc \
|
||||
src/common/module.cc \
|
||||
src/common/path_helper.cc \
|
||||
src/common/stabs_reader.cc \
|
||||
src/common/stabs_to_module.cc \
|
||||
src/common/test_assembler.cc \
|
||||
|
@ -747,17 +736,6 @@ src_common_mac_macho_reader_unittest_LDADD = \
|
|||
$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
|
||||
endif
|
||||
|
||||
src_common_linux_google_crashdump_uploader_test_SOURCES = \
|
||||
src/common/linux/google_crashdump_uploader.cc \
|
||||
src/common/linux/google_crashdump_uploader_test.cc \
|
||||
src/common/linux/libcurl_wrapper.cc
|
||||
src_common_linux_google_crashdump_uploader_test_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) $(TEST_CFLAGS)
|
||||
src_common_linux_google_crashdump_uploader_test_LDADD = \
|
||||
$(TEST_LIBS) \
|
||||
$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \
|
||||
-ldl
|
||||
|
||||
src_tools_linux_md2core_minidump_2_core_unittest_SOURCES = \
|
||||
src/tools/linux/md2core/minidump_memory_range_unittest.cc
|
||||
src_tools_linux_md2core_minidump_2_core_unittest_CPPFLAGS = \
|
||||
|
@ -1196,7 +1174,6 @@ src_processor_minidump_dump_LDADD = \
|
|||
src_processor_microdump_stackwalk_SOURCES = \
|
||||
src/processor/microdump_stackwalk.cc
|
||||
src_processor_microdump_stackwalk_LDADD = \
|
||||
src/common/path_helper.o \
|
||||
src/processor/basic_code_modules.o \
|
||||
src/processor/basic_source_line_resolver.o \
|
||||
src/processor/call_stack.o \
|
||||
|
@ -1230,7 +1207,6 @@ src_processor_microdump_stackwalk_LDADD = \
|
|||
src_processor_minidump_stackwalk_SOURCES = \
|
||||
src/processor/minidump_stackwalk.cc
|
||||
src_processor_minidump_stackwalk_LDADD = \
|
||||
src/common/path_helper.o \
|
||||
src/processor/basic_code_modules.o \
|
||||
src/processor/basic_source_line_resolver.o \
|
||||
src/processor/call_stack.o \
|
||||
|
@ -1345,7 +1321,6 @@ EXTRA_DIST = \
|
|||
src/common/windows/pdb_source_line_writer.h \
|
||||
src/common/windows/string_utils-inl.h \
|
||||
src/common/windows/string_utils.cc \
|
||||
src/processor/microdump_stackwalk_test_vars \
|
||||
src/processor/stackwalk_common.cc \
|
||||
src/processor/stackwalk_common.h \
|
||||
src/processor/stackwalker_selftest_sol.s \
|
||||
|
@ -1372,7 +1347,6 @@ EXTRA_DIST = \
|
|||
src/processor/testdata/linux_raise_sigabrt.dmp \
|
||||
src/processor/testdata/linux_stack_pointer_in_module.dmp \
|
||||
src/processor/testdata/linux_stack_pointer_in_stack.dmp \
|
||||
src/processor/testdata/linux_stack_pointer_in_stack_alt_name.dmp \
|
||||
src/processor/testdata/linux_stacksmash.dmp \
|
||||
src/processor/testdata/linux_write_to_nonwritable_module.dmp \
|
||||
src/processor/testdata/linux_write_to_nonwritable_region_math.dmp \
|
||||
|
@ -1388,7 +1362,6 @@ EXTRA_DIST = \
|
|||
src/processor/testdata/microdump.stackwalk-arm.out \
|
||||
src/processor/testdata/microdump.stackwalk.machine_readable-arm64.out \
|
||||
src/processor/testdata/microdump.stackwalk.machine_readable-arm.out \
|
||||
src/processor/testdata/microdump-withcrashreason.dmp \
|
||||
src/processor/testdata/microdump-x86.dmp \
|
||||
src/processor/testdata/minidump2.dmp \
|
||||
src/processor/testdata/minidump2.dump.out \
|
||||
|
@ -1418,61 +1391,54 @@ EXTRA_DIST = \
|
|||
src/processor/testdata/symbols/overflow/B0E1FC01EF48E39CAF5C881D2DF0C3840/overflow.sym \
|
||||
src/processor/testdata/symbols/test_app.pdb/5A9832E5287241C1838ED98914E9B7FF1/test_app.sym \
|
||||
src/processor/testdata/test_app.cc \
|
||||
src/testing/googletest/include/gtest/gtest.h \
|
||||
src/testing/googletest/include/gtest/gtest-death-test.h \
|
||||
src/testing/googletest/include/gtest/gtest-message.h \
|
||||
src/testing/googletest/include/gtest/gtest-param-test.h \
|
||||
src/testing/googletest/include/gtest/gtest-printers.h \
|
||||
src/testing/googletest/include/gtest/gtest-spi.h \
|
||||
src/testing/googletest/include/gtest/gtest-test-part.h \
|
||||
src/testing/googletest/include/gtest/gtest-typed-test.h \
|
||||
src/testing/googletest/include/gtest/gtest_pred_impl.h \
|
||||
src/testing/googletest/include/gtest/gtest_prod.h \
|
||||
src/testing/googletest/include/gtest/internal/custom/gtest-port.h \
|
||||
src/testing/googletest/include/gtest/internal/custom/gtest-printers.h \
|
||||
src/testing/googletest/include/gtest/internal/custom/gtest.h \
|
||||
src/testing/googletest/include/gtest/internal/gtest-death-test-internal.h \
|
||||
src/testing/googletest/include/gtest/internal/gtest-filepath.h \
|
||||
src/testing/googletest/include/gtest/internal/gtest-internal.h \
|
||||
src/testing/googletest/include/gtest/internal/gtest-linked_ptr.h \
|
||||
src/testing/googletest/include/gtest/internal/gtest-param-util-generated.h \
|
||||
src/testing/googletest/include/gtest/internal/gtest-param-util.h \
|
||||
src/testing/googletest/include/gtest/internal/gtest-port-arch.h \
|
||||
src/testing/googletest/include/gtest/internal/gtest-port.h \
|
||||
src/testing/googletest/include/gtest/internal/gtest-string.h \
|
||||
src/testing/googletest/include/gtest/internal/gtest-tuple.h \
|
||||
src/testing/googletest/include/gtest/internal/gtest-type-util.h \
|
||||
src/testing/googletest/src/gtest.cc \
|
||||
src/testing/googletest/src/gtest-death-test.cc \
|
||||
src/testing/googletest/src/gtest-filepath.cc \
|
||||
src/testing/googletest/src/gtest-internal-inl.h \
|
||||
src/testing/googletest/src/gtest-port.cc \
|
||||
src/testing/googletest/src/gtest-printers.cc \
|
||||
src/testing/googletest/src/gtest-test-part.cc \
|
||||
src/testing/googletest/src/gtest-typed-test.cc \
|
||||
src/testing/googlemock/include/gmock/gmock.h \
|
||||
src/testing/googlemock/include/gmock/gmock-actions.h \
|
||||
src/testing/googlemock/include/gmock/gmock-cardinalities.h \
|
||||
src/testing/googlemock/include/gmock/gmock-generated-actions.h \
|
||||
src/testing/googlemock/include/gmock/gmock-generated-function-mockers.h \
|
||||
src/testing/googlemock/include/gmock/gmock-generated-matchers.h \
|
||||
src/testing/googlemock/include/gmock/gmock-generated-nice-strict.h \
|
||||
src/testing/googlemock/include/gmock/gmock-matchers.h \
|
||||
src/testing/googlemock/include/gmock/gmock-more-actions.h \
|
||||
src/testing/googlemock/include/gmock/gmock-more-matchers.h \
|
||||
src/testing/googlemock/include/gmock/gmock-spec-builders.h \
|
||||
src/testing/googlemock/include/gmock/internal/custom/gmock-generated-actions.h \
|
||||
src/testing/googlemock/include/gmock/internal/custom/gmock-matchers.h \
|
||||
src/testing/googlemock/include/gmock/internal/custom/gmock-port.h \
|
||||
src/testing/googlemock/include/gmock/internal/gmock-generated-internal-utils.h \
|
||||
src/testing/googlemock/include/gmock/internal/gmock-internal-utils.h \
|
||||
src/testing/googlemock/include/gmock/internal/gmock-port.h \
|
||||
src/testing/googlemock/src/gmock.cc \
|
||||
src/testing/googlemock/src/gmock-cardinalities.cc \
|
||||
src/testing/googlemock/src/gmock-internal-utils.cc \
|
||||
src/testing/googlemock/src/gmock-matchers.cc \
|
||||
src/testing/googlemock/src/gmock-spec-builders.cc \
|
||||
src/testing/googlemock/src/gmock_main.cc \
|
||||
src/testing/gtest/include/gtest/gtest.h \
|
||||
src/testing/gtest/include/gtest/gtest-death-test.h \
|
||||
src/testing/gtest/include/gtest/gtest-message.h \
|
||||
src/testing/gtest/include/gtest/gtest-param-test.h \
|
||||
src/testing/gtest/include/gtest/gtest-printers.h \
|
||||
src/testing/gtest/include/gtest/gtest-spi.h \
|
||||
src/testing/gtest/include/gtest/gtest-test-part.h \
|
||||
src/testing/gtest/include/gtest/gtest-typed-test.h \
|
||||
src/testing/gtest/include/gtest/gtest_pred_impl.h \
|
||||
src/testing/gtest/include/gtest/gtest_prod.h \
|
||||
src/testing/gtest/include/gtest/internal/gtest-death-test-internal.h \
|
||||
src/testing/gtest/include/gtest/internal/gtest-filepath.h \
|
||||
src/testing/gtest/include/gtest/internal/gtest-internal.h \
|
||||
src/testing/gtest/include/gtest/internal/gtest-linked_ptr.h \
|
||||
src/testing/gtest/include/gtest/internal/gtest-param-util-generated.h \
|
||||
src/testing/gtest/include/gtest/internal/gtest-param-util.h \
|
||||
src/testing/gtest/include/gtest/internal/gtest-port.h \
|
||||
src/testing/gtest/include/gtest/internal/gtest-string.h \
|
||||
src/testing/gtest/include/gtest/internal/gtest-tuple.h \
|
||||
src/testing/gtest/include/gtest/internal/gtest-type-util.h \
|
||||
src/testing/gtest/src/gtest.cc \
|
||||
src/testing/gtest/src/gtest-death-test.cc \
|
||||
src/testing/gtest/src/gtest-filepath.cc \
|
||||
src/testing/gtest/src/gtest-internal-inl.h \
|
||||
src/testing/gtest/src/gtest-port.cc \
|
||||
src/testing/gtest/src/gtest-printers.cc \
|
||||
src/testing/gtest/src/gtest-test-part.cc \
|
||||
src/testing/gtest/src/gtest-typed-test.cc \
|
||||
src/testing/include/gmock/gmock.h \
|
||||
src/testing/include/gmock/gmock-actions.h \
|
||||
src/testing/include/gmock/gmock-cardinalities.h \
|
||||
src/testing/include/gmock/gmock-generated-actions.h \
|
||||
src/testing/include/gmock/gmock-generated-function-mockers.h \
|
||||
src/testing/include/gmock/gmock-generated-matchers.h \
|
||||
src/testing/include/gmock/gmock-generated-nice-strict.h \
|
||||
src/testing/include/gmock/gmock-matchers.h \
|
||||
src/testing/include/gmock/gmock-more-actions.h \
|
||||
src/testing/include/gmock/gmock-more-matchers.h \
|
||||
src/testing/include/gmock/gmock-spec-builders.h \
|
||||
src/testing/include/gmock/internal/gmock-generated-internal-utils.h \
|
||||
src/testing/include/gmock/internal/gmock-internal-utils.h \
|
||||
src/testing/include/gmock/internal/gmock-port.h \
|
||||
src/testing/src/gmock.cc \
|
||||
src/testing/src/gmock-cardinalities.cc \
|
||||
src/testing/src/gmock-internal-utils.cc \
|
||||
src/testing/src/gmock-matchers.cc \
|
||||
src/testing/src/gmock-spec-builders.cc \
|
||||
src/testing/src/gmock_main.cc \
|
||||
src/third_party/curl/COPYING \
|
||||
src/third_party/curl/curlbuild.h \
|
||||
src/third_party/curl/curl.h \
|
||||
|
|
|
@ -8,7 +8,7 @@ crash-reporting system.
|
|||
* [Bugs](https://bugs.chromium.org/p/google-breakpad/)
|
||||
* Discussion/Questions: [google-breakpad-discuss@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-discuss)
|
||||
* Developer/Reviews: [google-breakpad-dev@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-dev)
|
||||
* Tests: [![Build Status](https://travis-ci.org/google/breakpad.svg?branch=master)](https://travis-ci.org/google/breakpad) [![Build status](https://ci.appveyor.com/api/projects/status/eguv4emv2rhq68u2?svg=true)](https://ci.appveyor.com/project/vapier/breakpad)
|
||||
* Tests: [![Build Status](https://travis-ci.org/google/breakpad.svg?branch=master)](https://travis-ci.org/google/breakpad)
|
||||
* Coverage [![Coverity Status](https://scan.coverity.com/projects/9215/badge.svg)](https://scan.coverity.com/projects/google-breakpad)
|
||||
|
||||
## Getting started (from master)
|
||||
|
|
|
@ -1295,10 +1295,3 @@ AC_SUBST([am__tar])
|
|||
AC_SUBST([am__untar])
|
||||
]) # _AM_PROG_TAR
|
||||
|
||||
m4_include([m4/ax_append_compile_flags.m4])
|
||||
m4_include([m4/ax_append_flag.m4])
|
||||
m4_include([m4/ax_check_compile_flag.m4])
|
||||
m4_include([m4/ax_check_define.m4])
|
||||
m4_include([m4/ax_cxx_compile_stdcxx.m4])
|
||||
m4_include([m4/ax_pthread.m4])
|
||||
m4_include([m4/ax_require_defined.m4])
|
||||
|
|
|
@ -0,0 +1,347 @@
|
|||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand '-c -o'.
|
||||
|
||||
scriptversion=2012-10-14.11; # UTC
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# We need space, tab and new line, in precisely that order. Quoting is
|
||||
# there to prevent tools from complaining about whitespace usage.
|
||||
IFS=" "" $nl"
|
||||
|
||||
file_conv=
|
||||
|
||||
# func_file_conv build_file lazy
|
||||
# Convert a $build file to $host form and store it in $file
|
||||
# Currently only supports Windows hosts. If the determined conversion
|
||||
# type is listed in (the comma separated) LAZY, no conversion will
|
||||
# take place.
|
||||
func_file_conv ()
|
||||
{
|
||||
file=$1
|
||||
case $file in
|
||||
/ | /[!/]*) # absolute file, and not a UNC file
|
||||
if test -z "$file_conv"; then
|
||||
# lazily determine how to convert abs files
|
||||
case `uname -s` in
|
||||
MINGW*)
|
||||
file_conv=mingw
|
||||
;;
|
||||
CYGWIN*)
|
||||
file_conv=cygwin
|
||||
;;
|
||||
*)
|
||||
file_conv=wine
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case $file_conv/,$2, in
|
||||
*,$file_conv,*)
|
||||
;;
|
||||
mingw/*)
|
||||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
|
||||
;;
|
||||
cygwin/*)
|
||||
file=`cygpath -m "$file" || echo "$file"`
|
||||
;;
|
||||
wine/*)
|
||||
file=`winepath -w "$file" || echo "$file"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# func_cl_dashL linkdir
|
||||
# Make cl look for libraries in LINKDIR
|
||||
func_cl_dashL ()
|
||||
{
|
||||
func_file_conv "$1"
|
||||
if test -z "$lib_path"; then
|
||||
lib_path=$file
|
||||
else
|
||||
lib_path="$lib_path;$file"
|
||||
fi
|
||||
linker_opts="$linker_opts -LIBPATH:$file"
|
||||
}
|
||||
|
||||
# func_cl_dashl library
|
||||
# Do a library search-path lookup for cl
|
||||
func_cl_dashl ()
|
||||
{
|
||||
lib=$1
|
||||
found=no
|
||||
save_IFS=$IFS
|
||||
IFS=';'
|
||||
for dir in $lib_path $LIB
|
||||
do
|
||||
IFS=$save_IFS
|
||||
if $shared && test -f "$dir/$lib.dll.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.dll.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/$lib.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/lib$lib.a"; then
|
||||
found=yes
|
||||
lib=$dir/lib$lib.a
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$save_IFS
|
||||
|
||||
if test "$found" != yes; then
|
||||
lib=$lib.lib
|
||||
fi
|
||||
}
|
||||
|
||||
# func_cl_wrapper cl arg...
|
||||
# Adjust compile command to suit cl
|
||||
func_cl_wrapper ()
|
||||
{
|
||||
# Assume a capable shell
|
||||
lib_path=
|
||||
shared=:
|
||||
linker_opts=
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.[oO][bB][jJ])
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fo"$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fe"$file"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I)
|
||||
eat=1
|
||||
func_file_conv "$2" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-I*)
|
||||
func_file_conv "${1#-I}" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-l)
|
||||
eat=1
|
||||
func_cl_dashl "$2"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-l*)
|
||||
func_cl_dashl "${1#-l}"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-L)
|
||||
eat=1
|
||||
func_cl_dashL "$2"
|
||||
;;
|
||||
-L*)
|
||||
func_cl_dashL "${1#-L}"
|
||||
;;
|
||||
-static)
|
||||
shared=false
|
||||
;;
|
||||
-Wl,*)
|
||||
arg=${1#-Wl,}
|
||||
save_ifs="$IFS"; IFS=','
|
||||
for flag in $arg; do
|
||||
IFS="$save_ifs"
|
||||
linker_opts="$linker_opts $flag"
|
||||
done
|
||||
IFS="$save_ifs"
|
||||
;;
|
||||
-Xlinker)
|
||||
eat=1
|
||||
linker_opts="$linker_opts $2"
|
||||
;;
|
||||
-*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
|
||||
func_file_conv "$1"
|
||||
set x "$@" -Tp"$file"
|
||||
shift
|
||||
;;
|
||||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
|
||||
func_file_conv "$1" mingw
|
||||
set x "$@" "$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if test -n "$linker_opts"; then
|
||||
linker_opts="-link$linker_opts"
|
||||
fi
|
||||
exec "$@" $linker_opts
|
||||
exit 1
|
||||
}
|
||||
|
||||
eat=
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand '-c -o'.
|
||||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file 'INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
|
||||
func_cl_wrapper "$@" # Doesn't return...
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
# So we strip '-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no '-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# '.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,791 @@
|
|||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2013-05-30.07; # UTC
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program 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 General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||
as side-effects.
|
||||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by 'PROGRAMS ARGS'.
|
||||
object Object file output by 'PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputting dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
# Get the directory component of the given path, and save it in the
|
||||
# global variables '$dir'. Note that this directory component will
|
||||
# be either empty or ending with a '/' character. This is deliberate.
|
||||
set_dir_from ()
|
||||
{
|
||||
case $1 in
|
||||
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
|
||||
*) dir=;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get the suffix-stripped basename of the given path, and save it the
|
||||
# global variable '$base'.
|
||||
set_base_from ()
|
||||
{
|
||||
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
|
||||
}
|
||||
|
||||
# If no dependency file was actually created by the compiler invocation,
|
||||
# we still have to create a dummy depfile, to avoid errors with the
|
||||
# Makefile "include basename.Plo" scheme.
|
||||
make_dummy_depfile ()
|
||||
{
|
||||
echo "#dummy" > "$depfile"
|
||||
}
|
||||
|
||||
# Factor out some common post-processing of the generated depfile.
|
||||
# Requires the auxiliary global variable '$tmpdepfile' to be set.
|
||||
aix_post_process_depfile ()
|
||||
{
|
||||
# If the compiler actually managed to produce a dependency file,
|
||||
# post-process it.
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form 'foo.o: dependency.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# $object: dependency.h
|
||||
# and one to simply output
|
||||
# dependency.h:
|
||||
# which is needed to avoid the deleted-header problem.
|
||||
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
|
||||
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
|
||||
} > "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
}
|
||||
|
||||
# A tabulation character.
|
||||
tab=' '
|
||||
# A newline character.
|
||||
nl='
|
||||
'
|
||||
# Character ranges might be problematic outside the C locale.
|
||||
# These definitions help.
|
||||
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
lower=abcdefghijklmnopqrstuvwxyz
|
||||
digits=0123456789
|
||||
alpha=${upper}${lower}
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||
depfile=${depfile-`echo "$object" |
|
||||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Avoid interferences from the environment.
|
||||
gccflag= dashmflag=
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
cygpath_u="cygpath -u -f -"
|
||||
if test "$depmode" = msvcmsys; then
|
||||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
if test "$depmode" = msvc7msys; then
|
||||
# This is just like msvc7 but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvc7
|
||||
fi
|
||||
|
||||
if test "$depmode" = xlc; then
|
||||
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
|
||||
gccflag=-qmakedep=gcc,-MF
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
|
||||
## the command line argument order; so add the flags where they
|
||||
## appear in depend2.am. Note that the slowdown incurred here
|
||||
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
|
||||
*) set fnord "$@" "$arg" ;;
|
||||
esac
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
done
|
||||
"$@"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
|
||||
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
|
||||
## (see the conditional assignment to $gccflag above).
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say). Also, it might not be
|
||||
## supported by the other compilers which use the 'gcc' depmode.
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The second -e expression handles DOS-style file names with drive
|
||||
# letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the "deleted header file" problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
## Some versions of gcc put a space before the ':'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well. hp depmode also adds that space, but also prefixes the VPATH
|
||||
## to the object. Take care to not repeat it in the output.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like '#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
|
||||
| tr "$nl" ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
xlc)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts '$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$base.u
|
||||
tmpdepfile3=$dir.libs/$base.u
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$dir$base.u
|
||||
tmpdepfile3=$dir$base.u
|
||||
"$@" -M
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
tcc)
|
||||
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
|
||||
# FIXME: That version still under development at the moment of writing.
|
||||
# Make that this statement remains true also for stable, released
|
||||
# versions.
|
||||
# It will wrap lines (doesn't matter whether long or short) with a
|
||||
# trailing '\', as in:
|
||||
#
|
||||
# foo.o : \
|
||||
# foo.c \
|
||||
# foo.h \
|
||||
#
|
||||
# It will put a trailing '\' even on the last line, and will use leading
|
||||
# spaces rather than leading tabs (at least since its commit 0394caf7
|
||||
# "Emit spaces for -MD").
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
|
||||
# We have to change lines of the first kind to '$object: \'.
|
||||
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
|
||||
# And for each line of the second kind, we have to emit a 'dep.h:'
|
||||
# dummy dependency, to avoid the deleted-header problem.
|
||||
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
## The order of this option in the case statement is important, since the
|
||||
## shell code in configure will try each of these formats in the order
|
||||
## listed in this file. A plain '-MD' option would be understood by many
|
||||
## compilers, so we must ensure this comes after the gcc and icc options.
|
||||
pgcc)
|
||||
# Portland's C compiler understands '-MD'.
|
||||
# Will always output deps to 'file.d' where file is the root name of the
|
||||
# source file under compilation, even if file resides in a subdirectory.
|
||||
# The object file name does not affect the name of the '.d' file.
|
||||
# pgcc 10.2 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using '\' :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
set_dir_from "$object"
|
||||
# Use the source, not the object, to determine the base name, since
|
||||
# that's sadly what pgcc will do too.
|
||||
set_base_from "$source"
|
||||
tmpdepfile=$base.d
|
||||
|
||||
# For projects that build the same source file twice into different object
|
||||
# files, the pgcc approach of using the *source* file root name can cause
|
||||
# problems in parallel builds. Use a locking strategy to avoid stomping on
|
||||
# the same $tmpdepfile.
|
||||
lockdir=$base.d-lock
|
||||
trap "
|
||||
echo '$0: caught signal, cleaning up...' >&2
|
||||
rmdir '$lockdir'
|
||||
exit 1
|
||||
" 1 2 13 15
|
||||
numtries=100
|
||||
i=$numtries
|
||||
while test $i -gt 0; do
|
||||
# mkdir is a portable test-and-set.
|
||||
if mkdir "$lockdir" 2>/dev/null; then
|
||||
# This process acquired the lock.
|
||||
"$@" -MD
|
||||
stat=$?
|
||||
# Release the lock.
|
||||
rmdir "$lockdir"
|
||||
break
|
||||
else
|
||||
# If the lock is being held by a different process, wait
|
||||
# until the winning process is done or we timeout.
|
||||
while test -d "$lockdir" && test $i -gt 0; do
|
||||
sleep 1
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
fi
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
trap - 1 2 13 15
|
||||
if test $i -le 0; then
|
||||
echo "$0: failed to acquire lock after $numtries attempts" >&2
|
||||
echo "$0: check lockdir '$lockdir'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp2)
|
||||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
|
||||
# compilers, which have integrated preprocessors. The correct option
|
||||
# to use with these is +Maked; it writes dependencies to a file named
|
||||
# 'foo.d', which lands next to the object file, wherever that
|
||||
# happens to be.
|
||||
# Much of this is similar to the tru64 case; see comments there.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir.libs/$base.d
|
||||
"$@" -Wc,+Maked
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
"$@" +Maked
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add 'dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile" "$tmpdepfile2"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in 'foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# Libtool generates 2 separate objects for the 2 libraries. These
|
||||
# two compilations output dependencies in $dir.libs/$base.o.d and
|
||||
# in $dir$base.o.d. We have to check for both files, because
|
||||
# one of the two compilations can be disabled. We should prefer
|
||||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||
# the former would cause a distcleancheck panic.
|
||||
tmpdepfile1=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
|
||||
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
# Same post-processing that is required for AIX mode.
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
msvc7)
|
||||
if test "$libtool" = yes; then
|
||||
showIncludes=-Wc,-showIncludes
|
||||
else
|
||||
showIncludes=-showIncludes
|
||||
fi
|
||||
"$@" $showIncludes > "$tmpdepfile"
|
||||
stat=$?
|
||||
grep -v '^Note: including file: ' "$tmpdepfile"
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The first sed program below extracts the file names and escapes
|
||||
# backslashes for cygpath. The second sed program outputs the file
|
||||
# name when reading, but also accumulates all include files in the
|
||||
# hold buffer in order to output them again at the end. This only
|
||||
# works with sed implementations that can handle large buffers.
|
||||
sed < "$tmpdepfile" -n '
|
||||
/^Note: including file: *\(.*\)/ {
|
||||
s//\1/
|
||||
s/\\/\\\\/g
|
||||
p
|
||||
}' | $cygpath_u | sort -u | sed -n '
|
||||
s/ /\\ /g
|
||||
s/\(.*\)/'"$tab"'\1 \\/p
|
||||
s/.\(.*\) \\/\1:/
|
||||
H
|
||||
$ {
|
||||
s/.*/'"$tab"'/
|
||||
G
|
||||
p
|
||||
}' >> "$depfile"
|
||||
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7msys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout, regardless of -o.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for ':'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this sed invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
"$@" || exit $?
|
||||
# Remove any Libtool call
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
# X makedepend
|
||||
shift
|
||||
cleared=no eat=no
|
||||
for arg
|
||||
do
|
||||
case $cleared in
|
||||
no)
|
||||
set ""; shift
|
||||
cleared=yes ;;
|
||||
esac
|
||||
if test $eat = yes; then
|
||||
eat=no
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
# Strip any option that makedepend may not understand. Remove
|
||||
# the object too, otherwise makedepend will parse it as a source file.
|
||||
-arch)
|
||||
eat=yes ;;
|
||||
-*|$object)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
esac
|
||||
done
|
||||
obj_suffix=`echo "$object" | sed 's/^.*\././'`
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
# makedepend may prepend the VPATH from the source file name to the object.
|
||||
# No need to regex-escape $object, excess matching of '.' is harmless.
|
||||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process the last invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed '1,2d' "$tmpdepfile" \
|
||||
| tr ' ' "$nl" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
"$@" -E \
|
||||
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
| sed '$ s: \\$::' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E 2>/dev/null |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
|
||||
echo "$tab" >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvcmsys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,501 @@
|
|||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2013-12-25.23; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,215 @@
|
|||
#! /bin/sh
|
||||
# Common wrapper for a few potentially missing GNU programs.
|
||||
|
||||
scriptversion=2013-10-28.13; # UTC
|
||||
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program 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 General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
|
||||
--is-lightweight)
|
||||
# Used by our autoconf macros to check whether the available missing
|
||||
# script is modern enough.
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--run)
|
||||
# Back-compat with the calling convention used by older automake.
|
||||
shift
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
|
||||
to PROGRAM being missing or too old.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal autoconf autoheader autom4te automake makeinfo
|
||||
bison yacc flex lex help2man
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
|
||||
'g' are ignored when checking the name.
|
||||
|
||||
Send bug reports to <bug-automake@gnu.org>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing $scriptversion (GNU Automake)"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: unknown '$1' option"
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Run the given program, remember its exit status.
|
||||
"$@"; st=$?
|
||||
|
||||
# If it succeeded, we are done.
|
||||
test $st -eq 0 && exit 0
|
||||
|
||||
# Also exit now if we it failed (or wasn't found), and '--version' was
|
||||
# passed; such an option is passed most likely to detect whether the
|
||||
# program is present and works.
|
||||
case $2 in --version|--help) exit $st;; esac
|
||||
|
||||
# Exit code 63 means version mismatch. This often happens when the user
|
||||
# tries to use an ancient version of a tool on a file that requires a
|
||||
# minimum version.
|
||||
if test $st -eq 63; then
|
||||
msg="probably too old"
|
||||
elif test $st -eq 127; then
|
||||
# Program was missing.
|
||||
msg="missing on your system"
|
||||
else
|
||||
# Program was found and executed, but failed. Give up.
|
||||
exit $st
|
||||
fi
|
||||
|
||||
perl_URL=http://www.perl.org/
|
||||
flex_URL=http://flex.sourceforge.net/
|
||||
gnu_software_URL=http://www.gnu.org/software
|
||||
|
||||
program_details ()
|
||||
{
|
||||
case $1 in
|
||||
aclocal|automake)
|
||||
echo "The '$1' program is part of the GNU Automake package:"
|
||||
echo "<$gnu_software_URL/automake>"
|
||||
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/autoconf>"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
autoconf|autom4te|autoheader)
|
||||
echo "The '$1' program is part of the GNU Autoconf package:"
|
||||
echo "<$gnu_software_URL/autoconf/>"
|
||||
echo "It also requires GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice ()
|
||||
{
|
||||
# Normalize program name to check for.
|
||||
normalized_program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
printf '%s\n' "'$1' is $msg."
|
||||
|
||||
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
|
||||
case $normalized_program in
|
||||
autoconf*)
|
||||
echo "You should only need it if you modified 'configure.ac',"
|
||||
echo "or m4 files included by it."
|
||||
program_details 'autoconf'
|
||||
;;
|
||||
autoheader*)
|
||||
echo "You should only need it if you modified 'acconfig.h' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'autoheader'
|
||||
;;
|
||||
automake*)
|
||||
echo "You should only need it if you modified 'Makefile.am' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'automake'
|
||||
;;
|
||||
aclocal*)
|
||||
echo "You should only need it if you modified 'acinclude.m4' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'aclocal'
|
||||
;;
|
||||
autom4te*)
|
||||
echo "You might have modified some maintainer files that require"
|
||||
echo "the 'autom4te' program to be rebuilt."
|
||||
program_details 'autom4te'
|
||||
;;
|
||||
bison*|yacc*)
|
||||
echo "You should only need it if you modified a '.y' file."
|
||||
echo "You may want to install the GNU Bison package:"
|
||||
echo "<$gnu_software_URL/bison/>"
|
||||
;;
|
||||
lex*|flex*)
|
||||
echo "You should only need it if you modified a '.l' file."
|
||||
echo "You may want to install the Fast Lexical Analyzer package:"
|
||||
echo "<$flex_URL>"
|
||||
;;
|
||||
help2man*)
|
||||
echo "You should only need it if you modified a dependency" \
|
||||
"of a man page."
|
||||
echo "You may want to install the GNU Help2man package:"
|
||||
echo "<$gnu_software_URL/help2man/>"
|
||||
;;
|
||||
makeinfo*)
|
||||
echo "You should only need it if you modified a '.texi' file, or"
|
||||
echo "any other file indirectly affecting the aspect of the manual."
|
||||
echo "You might want to install the Texinfo package:"
|
||||
echo "<$gnu_software_URL/texinfo/>"
|
||||
echo "The spurious makeinfo call might also be the consequence of"
|
||||
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
|
||||
echo "want to install GNU make:"
|
||||
echo "<$gnu_software_URL/make/>"
|
||||
;;
|
||||
*)
|
||||
echo "You might have modified some files without having the proper"
|
||||
echo "tools for further handling them. Check the 'README' file, it"
|
||||
echo "often tells you about the needed prerequisites for installing"
|
||||
echo "this package. You may also peek at any GNU archive site, in"
|
||||
echo "case some other package contains this missing '$1' program."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice "$1" | sed -e '1s/^/WARNING: /' \
|
||||
-e '2,$s/^/ /' >&2
|
||||
|
||||
# Propagate the correct exit status (expected to be 127 for a program
|
||||
# not found, 63 for a program that failed due to version mismatch).
|
||||
exit $st
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,148 @@
|
|||
#! /bin/sh
|
||||
# test-driver - basic testsuite driver script.
|
||||
|
||||
scriptversion=2013-07-13.22; # UTC
|
||||
|
||||
# Copyright (C) 2011-2014 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
# Make unconditional expansion of undefined variables an error. This
|
||||
# helps a lot in preventing typo-related bugs.
|
||||
set -u
|
||||
|
||||
usage_error ()
|
||||
{
|
||||
echo "$0: $*" >&2
|
||||
print_usage >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
print_usage ()
|
||||
{
|
||||
cat <<END
|
||||
Usage:
|
||||
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
|
||||
[--expect-failure={yes|no}] [--color-tests={yes|no}]
|
||||
[--enable-hard-errors={yes|no}] [--]
|
||||
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
|
||||
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
|
||||
END
|
||||
}
|
||||
|
||||
test_name= # Used for reporting.
|
||||
log_file= # Where to save the output of the test script.
|
||||
trs_file= # Where to save the metadata of the test run.
|
||||
expect_failure=no
|
||||
color_tests=no
|
||||
enable_hard_errors=yes
|
||||
while test $# -gt 0; do
|
||||
case $1 in
|
||||
--help) print_usage; exit $?;;
|
||||
--version) echo "test-driver $scriptversion"; exit $?;;
|
||||
--test-name) test_name=$2; shift;;
|
||||
--log-file) log_file=$2; shift;;
|
||||
--trs-file) trs_file=$2; shift;;
|
||||
--color-tests) color_tests=$2; shift;;
|
||||
--expect-failure) expect_failure=$2; shift;;
|
||||
--enable-hard-errors) enable_hard_errors=$2; shift;;
|
||||
--) shift; break;;
|
||||
-*) usage_error "invalid option: '$1'";;
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
missing_opts=
|
||||
test x"$test_name" = x && missing_opts="$missing_opts --test-name"
|
||||
test x"$log_file" = x && missing_opts="$missing_opts --log-file"
|
||||
test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
|
||||
if test x"$missing_opts" != x; then
|
||||
usage_error "the following mandatory options are missing:$missing_opts"
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
usage_error "missing argument"
|
||||
fi
|
||||
|
||||
if test $color_tests = yes; then
|
||||
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
|
||||
red='[0;31m' # Red.
|
||||
grn='[0;32m' # Green.
|
||||
lgn='[1;32m' # Light green.
|
||||
blu='[1;34m' # Blue.
|
||||
mgn='[0;35m' # Magenta.
|
||||
std='[m' # No color.
|
||||
else
|
||||
red= grn= lgn= blu= mgn= std=
|
||||
fi
|
||||
|
||||
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
|
||||
trap "st=129; $do_exit" 1
|
||||
trap "st=130; $do_exit" 2
|
||||
trap "st=141; $do_exit" 13
|
||||
trap "st=143; $do_exit" 15
|
||||
|
||||
# Test script is run here.
|
||||
"$@" >$log_file 2>&1
|
||||
estatus=$?
|
||||
|
||||
if test $enable_hard_errors = no && test $estatus -eq 99; then
|
||||
tweaked_estatus=1
|
||||
else
|
||||
tweaked_estatus=$estatus
|
||||
fi
|
||||
|
||||
case $tweaked_estatus:$expect_failure in
|
||||
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
|
||||
0:*) col=$grn res=PASS recheck=no gcopy=no;;
|
||||
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
|
||||
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
|
||||
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
|
||||
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
|
||||
esac
|
||||
|
||||
# Report the test outcome and exit status in the logs, so that one can
|
||||
# know whether the test passed or failed simply by looking at the '.log'
|
||||
# file, without the need of also peaking into the corresponding '.trs'
|
||||
# file (automake bug#11814).
|
||||
echo "$res $test_name (exit status: $estatus)" >>$log_file
|
||||
|
||||
# Report outcome to console.
|
||||
echo "${col}${res}${std}: $test_name"
|
||||
|
||||
# Register the test result, and other relevant metadata.
|
||||
echo ":test-result: $res" > $trs_file
|
||||
echo ":global-test-result: $res" >> $trs_file
|
||||
echo ":recheck: $recheck" >> $trs_file
|
||||
echo ":copy-in-global-log: $gcopy" >> $trs_file
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -626,10 +626,6 @@ ac_subst_vars='am__EXEEXT_FALSE
|
|||
am__EXEEXT_TRUE
|
||||
LTLIBOBJS
|
||||
LIBOBJS
|
||||
TESTS_AS_ROOT_FALSE
|
||||
TESTS_AS_ROOT_TRUE
|
||||
RUST_DEMANGLE_LIBS
|
||||
RUST_DEMANGLE_CFLAGS
|
||||
SELFTEST_FALSE
|
||||
SELFTEST_TRUE
|
||||
GTEST_LIBS
|
||||
|
@ -650,7 +646,6 @@ ANDROID_HOST_FALSE
|
|||
ANDROID_HOST_TRUE
|
||||
LINUX_HOST_FALSE
|
||||
LINUX_HOST_TRUE
|
||||
WARN_CXXFLAGS
|
||||
HAVE_CXX11
|
||||
PTHREAD_CFLAGS
|
||||
PTHREAD_LIBS
|
||||
|
@ -658,6 +653,8 @@ PTHREAD_CC
|
|||
ax_pthread_config
|
||||
EGREP
|
||||
GREP
|
||||
GCC_FALSE
|
||||
GCC_TRUE
|
||||
RANLIB
|
||||
am__fastdepCXX_FALSE
|
||||
am__fastdepCXX_TRUE
|
||||
|
@ -778,8 +775,6 @@ enable_processor
|
|||
enable_tools
|
||||
enable_system_test_libs
|
||||
enable_selftest
|
||||
with_rust_demangle
|
||||
with_tests_as_root
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
host_alias
|
||||
|
@ -800,9 +795,7 @@ GMOCK_CFLAGS
|
|||
GMOCK_LIBS
|
||||
GTEST_CONFIG
|
||||
GTEST_CFLAGS
|
||||
GTEST_LIBS
|
||||
RUST_DEMANGLE_CFLAGS
|
||||
RUST_DEMANGLE_LIBS'
|
||||
GTEST_LIBS'
|
||||
|
||||
|
||||
# Initialize some variables set by options.
|
||||
|
@ -1440,17 +1433,6 @@ Optional Features:
|
|||
--enable-selftest Run extra tests with "make check" (may conflict with
|
||||
optimizations) (default is no)
|
||||
|
||||
Optional Packages:
|
||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
|
||||
--with-rust-demangle=/path/to/rust-demangle-capi
|
||||
Link against the rust-demangle library to demangle
|
||||
Rust language symbols during symbol dumping (default
|
||||
is no) Pass the path to the crate root.
|
||||
--with-tests-as-root Run the tests as root. Use this on platforms like
|
||||
travis-ci.org that require root privileges to use
|
||||
ptrace (default is no)
|
||||
|
||||
Some influential environment variables:
|
||||
CC C compiler command
|
||||
CFLAGS C compiler flags
|
||||
|
@ -1474,10 +1456,6 @@ Some influential environment variables:
|
|||
GTEST_CFLAGS
|
||||
Compiler flags for gtest
|
||||
GTEST_LIBS Linker flags for gtest
|
||||
RUST_DEMANGLE_CFLAGS
|
||||
Compiler flags for rust-demangle
|
||||
RUST_DEMANGLE_LIBS
|
||||
Linker flags for rust-demangle
|
||||
|
||||
Use these variables to override the choices made by `configure' or to help
|
||||
it to find libraries and programs with nonstandard names/locations.
|
||||
|
@ -1881,73 +1859,6 @@ $as_echo "$ac_res" >&6; }
|
|||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
|
||||
} # ac_fn_c_check_header_compile
|
||||
|
||||
# ac_fn_c_check_func LINENO FUNC VAR
|
||||
# ----------------------------------
|
||||
# Tests whether FUNC exists, setting the cache variable VAR accordingly
|
||||
ac_fn_c_check_func ()
|
||||
{
|
||||
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
|
||||
$as_echo_n "checking for $2... " >&6; }
|
||||
if eval \${$3+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
|
||||
For example, HP-UX 11i <limits.h> declares gettimeofday. */
|
||||
#define $2 innocuous_$2
|
||||
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char $2 (); below.
|
||||
Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
|
||||
<limits.h> exists even on freestanding compilers. */
|
||||
|
||||
#ifdef __STDC__
|
||||
# include <limits.h>
|
||||
#else
|
||||
# include <assert.h>
|
||||
#endif
|
||||
|
||||
#undef $2
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char $2 ();
|
||||
/* The GNU C library defines this for functions which it implements
|
||||
to always fail with ENOSYS. Some functions are actually named
|
||||
something starting with __ and the normal name is an alias. */
|
||||
#if defined __stub_$2 || defined __stub___$2
|
||||
choke me
|
||||
#endif
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return $2 ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
eval "$3=yes"
|
||||
else
|
||||
eval "$3=no"
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
fi
|
||||
eval ac_res=\$$3
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
$as_echo "$ac_res" >&6; }
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
|
||||
} # ac_fn_c_check_func
|
||||
cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
@ -5809,6 +5720,14 @@ else
|
|||
RANLIB="$ac_cv_prog_RANLIB"
|
||||
fi
|
||||
|
||||
if test "$GCC" = yes; then
|
||||
GCC_TRUE=
|
||||
GCC_FALSE='#'
|
||||
else
|
||||
GCC_TRUE='#'
|
||||
GCC_FALSE=
|
||||
fi
|
||||
# let the Makefile know if we're gcc
|
||||
|
||||
# Check whether --enable-m32 was given.
|
||||
if test "${enable_m32+set}" = set; then :
|
||||
|
@ -6273,6 +6192,104 @@ rm -rf conftest*
|
|||
|
||||
fi
|
||||
|
||||
# ===========================================================================
|
||||
# http://www.nongnu.org/autoconf-archive/ax_pthread.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro figures out how to build C programs using POSIX threads. It
|
||||
# sets the PTHREAD_LIBS output variable to the threads library and linker
|
||||
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
|
||||
# flags that are needed. (The user can also force certain compiler
|
||||
# flags/libs to be tested by setting these environment variables.)
|
||||
#
|
||||
# Also sets PTHREAD_CC to any special C compiler that is needed for
|
||||
# multi-threaded programs (defaults to the value of CC otherwise). (This
|
||||
# is necessary on AIX to use the special cc_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also link it with them as well. e.g. you should link with
|
||||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
#
|
||||
# If you are only building threads programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
# CC="$PTHREAD_CC"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
|
||||
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
#
|
||||
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
|
||||
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
|
||||
# is not found. If ACTION-IF-FOUND is not specified, the default action
|
||||
# will define HAVE_PTHREAD.
|
||||
#
|
||||
# Please let the authors know if this macro fails on any platform, or if
|
||||
# you have any other suggestions or comments. This macro was based on work
|
||||
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
|
||||
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
|
||||
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
|
||||
# grateful for the helpful feedback of numerous users.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program 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 General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 6
|
||||
|
||||
# This is what autoupdate's m4 run will expand. It fires
|
||||
# the warning (with _au_warn_XXX), outputs it into the
|
||||
# updated configure.ac (with AC_DIAGNOSE), and then outputs
|
||||
# the replacement expansion.
|
||||
|
||||
|
||||
# This is an auxiliary macro that is also run when
|
||||
# autoupdate runs m4. It simply calls m4_warning, but
|
||||
# we need a wrapper so that each warning is emitted only
|
||||
# once. We break the quoting in m4_warning's argument in
|
||||
# order to expand this macro's arguments, not AU_DEFUN's.
|
||||
|
||||
|
||||
# Finally, this is the expansion that is picked up by
|
||||
# autoconf. It tells the user to run autoupdate, and
|
||||
# then outputs the replacement expansion. We do not care
|
||||
# about autoupdate's warning because that contains
|
||||
# information on what to do *after* running autoupdate.
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -6645,30 +6662,79 @@ fi
|
|||
done
|
||||
|
||||
|
||||
for ac_header in a.out.h sys/random.h
|
||||
for ac_header in a.out.h
|
||||
do :
|
||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "a.out.h" "ac_cv_header_a_out_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_a_out_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
|
||||
#define HAVE_A_OUT_H 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
for ac_func in arc4random getrandom
|
||||
do :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
done
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the specified
|
||||
# version of the C++ standard. If necessary, add switches to CXXFLAGS to
|
||||
# enable support. VERSION may be '11' (for the C++11 standard) or '14'
|
||||
# (for the C++14 standard).
|
||||
#
|
||||
# The second argument, if specified, indicates whether you insist on an
|
||||
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
|
||||
# -std=c++11). If neither is specified, you get whatever works, with
|
||||
# preference for an extended mode.
|
||||
#
|
||||
# The third argument, if specified 'mandatory' or if left unspecified,
|
||||
# indicates that baseline support for the specified C++ standard is
|
||||
# required and that the macro should error out if no mode with that
|
||||
# support is found. If specified 'optional', then configuration proceeds
|
||||
# regardless, after defining HAVE_CXX${VERSION} if and only if a
|
||||
# supporting mode is found.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
|
||||
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
|
||||
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
|
||||
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
|
||||
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
|
||||
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 1
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -7331,176 +7397,6 @@ $as_echo "#define HAVE_CXX11 1" >>confdefs.h
|
|||
fi
|
||||
|
||||
|
||||
WARN_CXXFLAGS=
|
||||
ac_ext=cpp
|
||||
ac_cpp='$CXXCPP $CPPFLAGS'
|
||||
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
||||
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
|
||||
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts -Werror=unknown-warning-option" >&5
|
||||
$as_echo_n "checking whether C++ compiler accepts -Werror=unknown-warning-option... " >&6; }
|
||||
if ${ax_cv_check_cxxflags___Werror_unknown_warning_option+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
|
||||
ax_check_save_flags=$CXXFLAGS
|
||||
CXXFLAGS="$CXXFLAGS -Werror=unknown-warning-option"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_compile "$LINENO"; then :
|
||||
ax_cv_check_cxxflags___Werror_unknown_warning_option=yes
|
||||
else
|
||||
ax_cv_check_cxxflags___Werror_unknown_warning_option=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
CXXFLAGS=$ax_check_save_flags
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cxxflags___Werror_unknown_warning_option" >&5
|
||||
$as_echo "$ax_cv_check_cxxflags___Werror_unknown_warning_option" >&6; }
|
||||
if test "x$ax_cv_check_cxxflags___Werror_unknown_warning_option" = xyes; then :
|
||||
|
||||
ax_compiler_flags_test="-Werror=unknown-warning-option"
|
||||
|
||||
else
|
||||
|
||||
ax_compiler_flags_test=""
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for flag in -Wmissing-braces -Wnon-virtual-dtor -Woverloaded-virtual -Wreorder -Wsign-compare -Wunused-local-typedefs -Wunused-variable -Wvla ; do
|
||||
as_CACHEVAR=`$as_echo "ax_cv_check_cxxflags_${ax_compiler_flags_test}_$flag" | $as_tr_sh`
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $flag" >&5
|
||||
$as_echo_n "checking whether C++ compiler accepts $flag... " >&6; }
|
||||
if eval \${$as_CACHEVAR+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
|
||||
ax_check_save_flags=$CXXFLAGS
|
||||
CXXFLAGS="$CXXFLAGS ${ax_compiler_flags_test} $flag"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_compile "$LINENO"; then :
|
||||
eval "$as_CACHEVAR=yes"
|
||||
else
|
||||
eval "$as_CACHEVAR=no"
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
CXXFLAGS=$ax_check_save_flags
|
||||
fi
|
||||
eval ac_res=\$$as_CACHEVAR
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
$as_echo "$ac_res" >&6; }
|
||||
if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
|
||||
|
||||
if ${WARN_CXXFLAGS+:} false; then :
|
||||
|
||||
case " $WARN_CXXFLAGS " in #(
|
||||
*" $flag "*) :
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS already contains \$flag"; } >&5
|
||||
(: WARN_CXXFLAGS already contains $flag) 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; } ;; #(
|
||||
*) :
|
||||
|
||||
as_fn_append WARN_CXXFLAGS " $flag"
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS=\"\$WARN_CXXFLAGS\""; } >&5
|
||||
(: WARN_CXXFLAGS="$WARN_CXXFLAGS") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }
|
||||
;;
|
||||
esac
|
||||
|
||||
else
|
||||
|
||||
WARN_CXXFLAGS=$flag
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS=\"\$WARN_CXXFLAGS\""; } >&5
|
||||
(: WARN_CXXFLAGS="$WARN_CXXFLAGS") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }
|
||||
|
||||
fi
|
||||
|
||||
else
|
||||
:
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
as_fn_append WARN_CXXFLAGS " -Werror"
|
||||
ac_ext=c
|
||||
ac_cpp='$CPP $CPPFLAGS'
|
||||
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
||||
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
|
||||
ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for O_CLOEXEC defined in fcntl.h" >&5
|
||||
$as_echo_n "checking for O_CLOEXEC defined in fcntl.h... " >&6; }
|
||||
if ${ac_cv_defined_O_CLOEXEC_fcntl_h+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <fcntl.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
#ifdef O_CLOEXEC
|
||||
int ok;
|
||||
#else
|
||||
choke me
|
||||
#endif
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
ac_cv_defined_O_CLOEXEC_fcntl_h=yes
|
||||
else
|
||||
ac_cv_defined_O_CLOEXEC_fcntl_h=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined_O_CLOEXEC_fcntl_h" >&5
|
||||
$as_echo "$ac_cv_defined_O_CLOEXEC_fcntl_h" >&6; }
|
||||
if test $ac_cv_defined_O_CLOEXEC_fcntl_h != "no"; then :
|
||||
|
||||
else
|
||||
|
||||
$as_echo "#define O_CLOEXEC 0" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
# Only build Linux client libs when compiling for Linux
|
||||
case $host in
|
||||
*-*-linux* | *-android* )
|
||||
|
@ -7851,58 +7747,6 @@ else
|
|||
fi
|
||||
|
||||
|
||||
|
||||
# Check whether --with-rust-demangle was given.
|
||||
if test "${with_rust_demangle+set}" = set; then :
|
||||
withval=$with_rust_demangle; case "${withval}" in
|
||||
yes)
|
||||
as_fn_error $? "You must pass the path to the rust-demangle-capi crate for --with-rust-demangle" "$LINENO" 5
|
||||
;;
|
||||
no)
|
||||
rust_demangle=false
|
||||
;;
|
||||
*)
|
||||
if ! test -f "${withval}/Cargo.toml"; then
|
||||
as_fn_error $? "You must pass the path to the rust-demangle-capi crate for --with-rust-demangle" "$LINENO" 5
|
||||
fi
|
||||
RUST_DEMANGLE_CFLAGS="-DHAVE_RUST_DEMANGLE -I${withval}/target/include"
|
||||
RUST_DEMANGLE_LIBS="-L${withval}/target/release -lrust_demangle -lpthread -ldl"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
rust_demangle=false
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Check whether --with-tests-as-root was given.
|
||||
if test "${with_tests_as_root+set}" = set; then :
|
||||
withval=$with_tests_as_root; case "${withval}" in
|
||||
yes)
|
||||
tests_as_root=true
|
||||
;;
|
||||
no)
|
||||
tests_as_root=false
|
||||
;;
|
||||
*)
|
||||
as_fn_error $? "--with-tests-as-root can only be \"yes\" or \"no\"" "$LINENO" 5
|
||||
;;
|
||||
esac
|
||||
else
|
||||
tests_as_root=false
|
||||
fi
|
||||
|
||||
if test x$tests_as_root = xtrue; then
|
||||
TESTS_AS_ROOT_TRUE=
|
||||
TESTS_AS_ROOT_FALSE='#'
|
||||
else
|
||||
TESTS_AS_ROOT_TRUE='#'
|
||||
TESTS_AS_ROOT_FALSE=
|
||||
fi
|
||||
|
||||
|
||||
ac_config_files="$ac_config_files breakpad.pc breakpad-client.pc Makefile"
|
||||
|
||||
|
||||
|
@ -8054,6 +7898,10 @@ if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
|
|||
as_fn_error $? "conditional \"am__fastdepCXX\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${GCC_TRUE}" && test -z "${GCC_FALSE}"; then
|
||||
as_fn_error $? "conditional \"GCC\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${LINUX_HOST_TRUE}" && test -z "${LINUX_HOST_FALSE}"; then
|
||||
as_fn_error $? "conditional \"LINUX_HOST\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
|
@ -8082,10 +7930,6 @@ if test -z "${SELFTEST_TRUE}" && test -z "${SELFTEST_FALSE}"; then
|
|||
as_fn_error $? "conditional \"SELFTEST\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${TESTS_AS_ROOT_TRUE}" && test -z "${TESTS_AS_ROOT_FALSE}"; then
|
||||
as_fn_error $? "conditional \"TESTS_AS_ROOT\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
|
||||
: "${CONFIG_STATUS=./config.status}"
|
||||
ac_write_fail=0
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
AC_PREREQ(2.64)
|
||||
AC_PREREQ(2.57)
|
||||
|
||||
AC_INIT(breakpad, 0.1, google-breakpad-dev@googlegroups.com)
|
||||
dnl Sanity check: the argument is just a file that should exist.
|
||||
|
@ -48,6 +48,7 @@ AM_PROG_CC_C_O
|
|||
AC_PROG_CPP
|
||||
AC_PROG_CXX
|
||||
AC_PROG_RANLIB
|
||||
AM_CONDITIONAL(GCC, test "$GCC" = yes) # let the Makefile know if we're gcc
|
||||
|
||||
dnl This must come before all the feature tests below.
|
||||
AC_ARG_ENABLE(m32,
|
||||
|
@ -71,40 +72,13 @@ AC_ARG_ENABLE(m32,
|
|||
|
||||
AC_HEADER_STDC
|
||||
AC_SYS_LARGEFILE
|
||||
m4_include(m4/ax_pthread.m4)
|
||||
AX_PTHREAD
|
||||
AC_CHECK_HEADERS([a.out.h sys/random.h])
|
||||
AC_CHECK_FUNCS([arc4random getrandom])
|
||||
AC_CHECK_HEADERS([a.out.h])
|
||||
|
||||
m4_include(m4/ax_cxx_compile_stdcxx.m4)
|
||||
AX_CXX_COMPILE_STDCXX(11, noext, mandatory)
|
||||
|
||||
dnl Test supported warning flags.
|
||||
WARN_CXXFLAGS=
|
||||
dnl This warning flag is used by clang. Its default behavior is to warn when
|
||||
dnl given an unknown flag rather than error out.
|
||||
AC_LANG_PUSH([C++])
|
||||
AX_CHECK_COMPILE_FLAG([-Werror=unknown-warning-option],[
|
||||
ax_compiler_flags_test="-Werror=unknown-warning-option"
|
||||
],[
|
||||
ax_compiler_flags_test=""
|
||||
])
|
||||
AX_APPEND_COMPILE_FLAGS(m4_flatten([
|
||||
-Wmissing-braces
|
||||
-Wnon-virtual-dtor
|
||||
-Woverloaded-virtual
|
||||
-Wreorder
|
||||
-Wsign-compare
|
||||
-Wunused-local-typedefs
|
||||
-Wunused-variable
|
||||
-Wvla
|
||||
]), [WARN_CXXFLAGS], [${ax_compiler_flags_test}])
|
||||
AS_VAR_APPEND([WARN_CXXFLAGS], " -Werror")
|
||||
AC_LANG_POP([C++])
|
||||
AC_SUBST([WARN_CXXFLAGS])
|
||||
|
||||
dnl Test support for O_CLOEXEC
|
||||
AX_CHECK_DEFINE([fcntl.h], [O_CLOEXEC], [],
|
||||
[AC_DEFINE([O_CLOEXEC], [0], [Fallback definition for old systems])])
|
||||
|
||||
# Only build Linux client libs when compiling for Linux
|
||||
case $host in
|
||||
*-*-linux* | *-android* )
|
||||
|
@ -221,50 +195,6 @@ AC_ARG_ENABLE(selftest,
|
|||
[selftest=false])
|
||||
AM_CONDITIONAL(SELFTEST, test x$selftest = xtrue)
|
||||
|
||||
AC_ARG_WITH(rust-demangle,
|
||||
AS_HELP_STRING([--with-rust-demangle=/path/to/rust-demangle-capi],
|
||||
[Link against the rust-demangle library]
|
||||
[to demangle Rust language symbols during]
|
||||
[symbol dumping (default is no)]
|
||||
[Pass the path to the crate root.]),
|
||||
[case "${withval}" in
|
||||
yes)
|
||||
AC_MSG_ERROR(You must pass the path to the rust-demangle-capi crate for --with-rust-demangle)
|
||||
;;
|
||||
no)
|
||||
rust_demangle=false
|
||||
;;
|
||||
*)
|
||||
if ! test -f "${withval}/Cargo.toml"; then
|
||||
AC_MSG_ERROR(You must pass the path to the rust-demangle-capi crate for --with-rust-demangle)
|
||||
fi
|
||||
RUST_DEMANGLE_CFLAGS="-DHAVE_RUST_DEMANGLE -I${withval}/target/include"
|
||||
RUST_DEMANGLE_LIBS="-L${withval}/target/release -lrust_demangle -lpthread -ldl"
|
||||
;;
|
||||
esac],
|
||||
[rust_demangle=false])
|
||||
AC_ARG_VAR([RUST_DEMANGLE_CFLAGS], [Compiler flags for rust-demangle])
|
||||
AC_ARG_VAR([RUST_DEMANGLE_LIBS], [Linker flags for rust-demangle])
|
||||
|
||||
AC_ARG_WITH(tests-as-root,
|
||||
AS_HELP_STRING([--with-tests-as-root],
|
||||
[Run the tests as root. Use this on platforms]
|
||||
[like travis-ci.org that require root privileges]
|
||||
[to use ptrace (default is no)]),
|
||||
[case "${withval}" in
|
||||
yes)
|
||||
tests_as_root=true
|
||||
;;
|
||||
no)
|
||||
tests_as_root=false
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR(--with-tests-as-root can only be "yes" or "no")
|
||||
;;
|
||||
esac],
|
||||
[tests_as_root=false])
|
||||
AM_CONDITIONAL(TESTS_AS_ROOT, test x$tests_as_root = xtrue)
|
||||
|
||||
AC_CONFIG_FILES(m4_flatten([
|
||||
breakpad.pc
|
||||
breakpad-client.pc
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- AUTOGENERATED BY deps-to-manifest.py; DO NOT EDIT -->
|
||||
<manifest>
|
||||
|
||||
<default revision='refs/heads/master'
|
||||
remote='chromium'
|
||||
sync-c='true'
|
||||
sync-j='8' />
|
||||
|
||||
<remote name='github'
|
||||
fetch='https://github.com/'
|
||||
review='' />
|
||||
|
||||
<remote name='chromium'
|
||||
fetch='https://chromium.googlesource.com/'
|
||||
review='https://chromium-review.googlesource.com' />
|
||||
|
||||
<project path='src'
|
||||
name='breakpad/breakpad'
|
||||
revision='refs/heads/master'
|
||||
remote='chromium' />
|
||||
|
||||
<project path='src/src/tools/gyp'
|
||||
name='external/gyp/'
|
||||
revision='324dd166b7c0b39d513026fa52d6280ac6d56770'
|
||||
remote='chromium' />
|
||||
|
||||
<project path='src/src/testing'
|
||||
name='google/googletest.git'
|
||||
revision='refs/tags/release-1.8.0'
|
||||
remote='github' />
|
||||
|
||||
<project path='src/src/third_party/lss'
|
||||
name='linux-syscall-support/'
|
||||
revision='e6527b0cd469e3ff5764785dadcb39bf7d787154'
|
||||
remote='chromium' />
|
||||
|
||||
<project path='src/src/third_party/protobuf/protobuf'
|
||||
name='google/protobuf.git'
|
||||
revision='cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac'
|
||||
remote='github' />
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,283 @@
|
|||
# ===========================================================================
|
||||
# http://www.nongnu.org/autoconf-archive/ax_pthread.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro figures out how to build C programs using POSIX threads. It
|
||||
# sets the PTHREAD_LIBS output variable to the threads library and linker
|
||||
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
|
||||
# flags that are needed. (The user can also force certain compiler
|
||||
# flags/libs to be tested by setting these environment variables.)
|
||||
#
|
||||
# Also sets PTHREAD_CC to any special C compiler that is needed for
|
||||
# multi-threaded programs (defaults to the value of CC otherwise). (This
|
||||
# is necessary on AIX to use the special cc_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also link it with them as well. e.g. you should link with
|
||||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
#
|
||||
# If you are only building threads programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
# CC="$PTHREAD_CC"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
|
||||
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
#
|
||||
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
|
||||
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
|
||||
# is not found. If ACTION-IF-FOUND is not specified, the default action
|
||||
# will define HAVE_PTHREAD.
|
||||
#
|
||||
# Please let the authors know if this macro fails on any platform, or if
|
||||
# you have any other suggestions or comments. This macro was based on work
|
||||
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
|
||||
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
|
||||
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
|
||||
# grateful for the helpful feedback of numerous users.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program 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 General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 6
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
ax_pthread_ok=no
|
||||
|
||||
# We used to check for pthread.h first, but this fails if pthread.h
|
||||
# requires special compiler flags (e.g. on True64 or Sequent).
|
||||
# It gets checked for in the link test anyway.
|
||||
|
||||
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||
# etcetera environment variables, and if threads linking works using
|
||||
# them:
|
||||
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
|
||||
AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
|
||||
AC_MSG_RESULT($ax_pthread_ok)
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
fi
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
fi
|
||||
|
||||
# We must check for the threads library under a number of different
|
||||
# names; the ordering is very important because some systems
|
||||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||
# libraries is broken (non-POSIX).
|
||||
|
||||
# Create a list of thread flags to try. Items starting with a "-" are
|
||||
# C compiler flags, and other items are library names, except for "none"
|
||||
# which indicates that we try without any flags at all, and "pthread-config"
|
||||
# which is a program returning the flags for the Pth emulation library.
|
||||
|
||||
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
|
||||
# pthreads: AIX (must check this before -lpthread)
|
||||
# none: in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
|
||||
# -pthreads: Solaris/gcc
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case "${host_cpu}-${host_os}" in
|
||||
*solaris*)
|
||||
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
|
||||
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
*-darwin*)
|
||||
acx_pthread_flags="-pthread $acx_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
for flag in $ax_pthread_flags; do
|
||||
|
||||
case $flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $flag])
|
||||
PTHREAD_CFLAGS="$flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
|
||||
if test x"$ax_pthread_config" = xno; then continue; fi
|
||||
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||||
PTHREAD_LIBS="-l$flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
save_LIBS="$LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
# need a special flag -Kthread to make this header compile.)
|
||||
# We check for pthread_join because it is in -lpthread on IRIX
|
||||
# while pthread_create is in libc. We check for pthread_attr_init
|
||||
# due to DEC craziness with -lpthreads. We check for
|
||||
# pthread_cleanup_push because it is one of the few pthread
|
||||
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||
# We try pthread_create on general principles.
|
||||
AC_TRY_LINK([#include <pthread.h>
|
||||
static void routine(void* a) {a=0;}
|
||||
static void* start_routine(void* a) {return a;}],
|
||||
[pthread_t th; pthread_attr_t attr;
|
||||
pthread_join(th, 0);
|
||||
pthread_attr_init(&attr);
|
||||
pthread_cleanup_push(routine, 0);
|
||||
pthread_create(&th,0,start_routine,0);
|
||||
pthread_cleanup_pop(0); ],
|
||||
[ax_pthread_ok=yes])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
AC_MSG_RESULT($ax_pthread_ok)
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
break;
|
||||
fi
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
done
|
||||
fi
|
||||
|
||||
# Various other checks:
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
|
||||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||
AC_MSG_CHECKING([for joinable pthread attribute])
|
||||
attr_name=unknown
|
||||
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
|
||||
[attr_name=$attr; break])
|
||||
done
|
||||
AC_MSG_RESULT($attr_name)
|
||||
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
|
||||
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||||
flag=no
|
||||
case "${host_cpu}-${host_os}" in
|
||||
*-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
|
||||
*solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
|
||||
esac
|
||||
AC_MSG_RESULT(${flag})
|
||||
if test "x$flag" != xno; then
|
||||
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||||
fi
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
# More AIX lossage: must compile with xlc_r or cc_r
|
||||
if test x"$GCC" != xyes; then
|
||||
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
|
||||
else
|
||||
PTHREAD_CC=$CC
|
||||
fi
|
||||
else
|
||||
PTHREAD_CC="$CC"
|
||||
fi
|
||||
|
||||
AC_SUBST(PTHREAD_LIBS)
|
||||
AC_SUBST(PTHREAD_CFLAGS)
|
||||
AC_SUBST(PTHREAD_CC)
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test x"$ax_pthread_ok" = xyes; then
|
||||
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
|
||||
:
|
||||
else
|
||||
ax_pthread_ok=no
|
||||
$2
|
||||
fi
|
||||
AC_LANG_RESTORE
|
||||
])dnl AX_PTHREAD
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,368 @@
|
|||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 6 ltoptions.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
|
||||
|
||||
|
||||
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ------------------------------------------
|
||||
m4_define([_LT_MANGLE_OPTION],
|
||||
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ---------------------------------------
|
||||
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
|
||||
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
|
||||
# saved as a flag.
|
||||
m4_define([_LT_SET_OPTION],
|
||||
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
|
||||
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
[m4_warning([Unknown $1 option `$2'])])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
|
||||
# ------------------------------------------------------------
|
||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||
m4_define([_LT_IF_OPTION],
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
|
||||
|
||||
|
||||
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
|
||||
# -------------------------------------------------------
|
||||
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
|
||||
# are set.
|
||||
m4_define([_LT_UNLESS_OPTIONS],
|
||||
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
|
||||
[m4_define([$0_found])])])[]dnl
|
||||
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
|
||||
])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
|
||||
# ----------------------------------------
|
||||
# OPTION-LIST is a space-separated list of Libtool options associated
|
||||
# with MACRO-NAME. If any OPTION has a matching handler declared with
|
||||
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
|
||||
# the unknown option and exit.
|
||||
m4_defun([_LT_SET_OPTIONS],
|
||||
[# Set options
|
||||
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[_LT_SET_OPTION([$1], _LT_Option)])
|
||||
|
||||
m4_if([$1],[LT_INIT],[
|
||||
dnl
|
||||
dnl Simply set some default values (i.e off) if boolean options were not
|
||||
dnl specified:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
|
||||
])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
|
||||
])
|
||||
dnl
|
||||
dnl If no reference was made to various pairs of opposing options, then
|
||||
dnl we run the default mode handler for the pair. For example, if neither
|
||||
dnl `shared' nor `disable-shared' was passed, we enable building of shared
|
||||
dnl archives by default:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
|
||||
[_LT_ENABLE_FAST_INSTALL])
|
||||
])
|
||||
])# _LT_SET_OPTIONS
|
||||
|
||||
|
||||
## --------------------------------- ##
|
||||
## Macros to handle LT_INIT options. ##
|
||||
## --------------------------------- ##
|
||||
|
||||
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
|
||||
# -----------------------------------------
|
||||
m4_define([_LT_MANGLE_DEFUN],
|
||||
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
|
||||
# -----------------------------------------------
|
||||
m4_define([LT_OPTION_DEFINE],
|
||||
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
|
||||
])# LT_OPTION_DEFINE
|
||||
|
||||
|
||||
# dlopen
|
||||
# ------
|
||||
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_DLOPEN],
|
||||
[_LT_SET_OPTION([LT_INIT], [dlopen])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the `dlopen' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
|
||||
|
||||
|
||||
# win32-dll
|
||||
# ---------
|
||||
# Declare package support for building win32 dll's.
|
||||
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
|
||||
[enable_win32_dll=yes
|
||||
|
||||
case $host in
|
||||
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*)
|
||||
AC_CHECK_TOOL(AS, as, false)
|
||||
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
|
||||
AC_CHECK_TOOL(OBJDUMP, objdump, false)
|
||||
;;
|
||||
esac
|
||||
|
||||
test -z "$AS" && AS=as
|
||||
_LT_DECL([], [AS], [0], [Assembler program])dnl
|
||||
|
||||
test -z "$DLLTOOL" && DLLTOOL=dlltool
|
||||
_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl
|
||||
|
||||
test -z "$OBJDUMP" && OBJDUMP=objdump
|
||||
_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl
|
||||
])# win32-dll
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
|
||||
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
|
||||
_LT_SET_OPTION([LT_INIT], [win32-dll])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the `win32-dll' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
|
||||
|
||||
|
||||
# _LT_ENABLE_SHARED([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-shared flag, and supports the `shared' and
|
||||
# `disable-shared' LT_INIT options.
|
||||
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
|
||||
m4_define([_LT_ENABLE_SHARED],
|
||||
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([shared],
|
||||
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
|
||||
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_shared=yes ;;
|
||||
no) enable_shared=no ;;
|
||||
*)
|
||||
enable_shared=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
|
||||
for pkg in $enableval; do
|
||||
IFS="$lt_save_ifs"
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_shared=yes
|
||||
fi
|
||||
done
|
||||
IFS="$lt_save_ifs"
|
||||
;;
|
||||
esac],
|
||||
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
|
||||
|
||||
_LT_DECL([build_libtool_libs], [enable_shared], [0],
|
||||
[Whether or not to build shared libraries])
|
||||
])# _LT_ENABLE_SHARED
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-shared])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
|
||||
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_STATIC([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-static flag, and support the `static' and
|
||||
# `disable-static' LT_INIT options.
|
||||
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
|
||||
m4_define([_LT_ENABLE_STATIC],
|
||||
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([static],
|
||||
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
|
||||
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_static=yes ;;
|
||||
no) enable_static=no ;;
|
||||
*)
|
||||
enable_static=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
|
||||
for pkg in $enableval; do
|
||||
IFS="$lt_save_ifs"
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_static=yes
|
||||
fi
|
||||
done
|
||||
IFS="$lt_save_ifs"
|
||||
;;
|
||||
esac],
|
||||
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
|
||||
|
||||
_LT_DECL([build_old_libs], [enable_static], [0],
|
||||
[Whether or not to build static libraries])
|
||||
])# _LT_ENABLE_STATIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-static])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
|
||||
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
|
||||
# ----------------------------------
|
||||
# implement the --enable-fast-install flag, and support the `fast-install'
|
||||
# and `disable-fast-install' LT_INIT options.
|
||||
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
|
||||
m4_define([_LT_ENABLE_FAST_INSTALL],
|
||||
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([fast-install],
|
||||
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
|
||||
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_fast_install=yes ;;
|
||||
no) enable_fast_install=no ;;
|
||||
*)
|
||||
enable_fast_install=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
|
||||
for pkg in $enableval; do
|
||||
IFS="$lt_save_ifs"
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_fast_install=yes
|
||||
fi
|
||||
done
|
||||
IFS="$lt_save_ifs"
|
||||
;;
|
||||
esac],
|
||||
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
|
||||
|
||||
_LT_DECL([fast_install], [enable_fast_install], [0],
|
||||
[Whether or not to optimize for fast installation])dnl
|
||||
])# _LT_ENABLE_FAST_INSTALL
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
|
||||
|
||||
# Old names:
|
||||
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the `fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the `disable-fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
|
||||
|
||||
|
||||
# _LT_WITH_PIC([MODE])
|
||||
# --------------------
|
||||
# implement the --with-pic flag, and support the `pic-only' and `no-pic'
|
||||
# LT_INIT options.
|
||||
# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
|
||||
m4_define([_LT_WITH_PIC],
|
||||
[AC_ARG_WITH([pic],
|
||||
[AS_HELP_STRING([--with-pic],
|
||||
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
|
||||
[pic_mode="$withval"],
|
||||
[pic_mode=default])
|
||||
|
||||
test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
|
||||
|
||||
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
|
||||
])# _LT_WITH_PIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
|
||||
|
||||
# Old name:
|
||||
AU_DEFUN([AC_LIBTOOL_PICMODE],
|
||||
[_LT_SET_OPTION([LT_INIT], [pic-only])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the `pic-only' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
|
||||
|
||||
## ----------------- ##
|
||||
## LTDL_INIT Options ##
|
||||
## ----------------- ##
|
||||
|
||||
m4_define([_LTDL_MODE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
|
||||
[m4_define([_LTDL_MODE], [nonrecursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
|
||||
[m4_define([_LTDL_MODE], [recursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
|
||||
[m4_define([_LTDL_MODE], [subproject])])
|
||||
|
||||
m4_define([_LTDL_TYPE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [installable],
|
||||
[m4_define([_LTDL_TYPE], [installable])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
|
||||
[m4_define([_LTDL_TYPE], [convenience])])
|
|
@ -0,0 +1,123 @@
|
|||
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 6 ltsugar.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
|
||||
|
||||
|
||||
# lt_join(SEP, ARG1, [ARG2...])
|
||||
# -----------------------------
|
||||
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
|
||||
# associated separator.
|
||||
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
|
||||
# versions in m4sugar had bugs.
|
||||
m4_define([lt_join],
|
||||
[m4_if([$#], [1], [],
|
||||
[$#], [2], [[$2]],
|
||||
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
m4_define([_lt_join],
|
||||
[m4_if([$#$2], [2], [],
|
||||
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
|
||||
|
||||
# lt_car(LIST)
|
||||
# lt_cdr(LIST)
|
||||
# ------------
|
||||
# Manipulate m4 lists.
|
||||
# These macros are necessary as long as will still need to support
|
||||
# Autoconf-2.59 which quotes differently.
|
||||
m4_define([lt_car], [[$1]])
|
||||
m4_define([lt_cdr],
|
||||
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
|
||||
[$#], 1, [],
|
||||
[m4_dquote(m4_shift($@))])])
|
||||
m4_define([lt_unquote], $1)
|
||||
|
||||
|
||||
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
|
||||
# ------------------------------------------
|
||||
# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
|
||||
# Note that neither SEPARATOR nor STRING are expanded; they are appended
|
||||
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
|
||||
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
|
||||
# than defined and empty).
|
||||
#
|
||||
# This macro is needed until we can rely on Autoconf 2.62, since earlier
|
||||
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
|
||||
m4_define([lt_append],
|
||||
[m4_define([$1],
|
||||
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
|
||||
|
||||
|
||||
|
||||
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
|
||||
# ----------------------------------------------------------
|
||||
# Produce a SEP delimited list of all paired combinations of elements of
|
||||
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
|
||||
# has the form PREFIXmINFIXSUFFIXn.
|
||||
# Needed until we can rely on m4_combine added in Autoconf 2.62.
|
||||
m4_define([lt_combine],
|
||||
[m4_if(m4_eval([$# > 3]), [1],
|
||||
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
|
||||
[[m4_foreach([_Lt_prefix], [$2],
|
||||
[m4_foreach([_Lt_suffix],
|
||||
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
|
||||
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
|
||||
|
||||
|
||||
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
|
||||
# -----------------------------------------------------------------------
|
||||
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
|
||||
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
|
||||
m4_define([lt_if_append_uniq],
|
||||
[m4_ifdef([$1],
|
||||
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
|
||||
[lt_append([$1], [$2], [$3])$4],
|
||||
[$5])],
|
||||
[lt_append([$1], [$2], [$3])$4])])
|
||||
|
||||
|
||||
# lt_dict_add(DICT, KEY, VALUE)
|
||||
# -----------------------------
|
||||
m4_define([lt_dict_add],
|
||||
[m4_define([$1($2)], [$3])])
|
||||
|
||||
|
||||
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
|
||||
# --------------------------------------------
|
||||
m4_define([lt_dict_add_subkey],
|
||||
[m4_define([$1($2:$3)], [$4])])
|
||||
|
||||
|
||||
# lt_dict_fetch(DICT, KEY, [SUBKEY])
|
||||
# ----------------------------------
|
||||
m4_define([lt_dict_fetch],
|
||||
[m4_ifval([$3],
|
||||
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
|
||||
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
|
||||
|
||||
|
||||
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
|
||||
# -----------------------------------------------------------------
|
||||
m4_define([lt_if_dict_fetch],
|
||||
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
|
||||
[$5],
|
||||
[$6])])
|
||||
|
||||
|
||||
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
|
||||
# --------------------------------------------------------------
|
||||
m4_define([lt_dict_filter],
|
||||
[m4_if([$5], [], [],
|
||||
[lt_join(m4_quote(m4_default([$4], [[, ]])),
|
||||
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
|
||||
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
|
||||
])
|
|
@ -0,0 +1,23 @@
|
|||
# ltversion.m4 -- version numbers -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# Generated from ltversion.in.
|
||||
|
||||
# serial 3017 ltversion.m4
|
||||
# This file is part of GNU Libtool
|
||||
|
||||
m4_define([LT_PACKAGE_VERSION], [2.2.6b])
|
||||
m4_define([LT_PACKAGE_REVISION], [1.3017])
|
||||
|
||||
AC_DEFUN([LTVERSION_VERSION],
|
||||
[macro_version='2.2.6b'
|
||||
macro_revision='1.3017'
|
||||
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
|
||||
_LT_DECL(, macro_revision, 0)
|
||||
])
|
|
@ -0,0 +1,92 @@
|
|||
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4 lt~obsolete.m4
|
||||
|
||||
# These exist entirely to fool aclocal when bootstrapping libtool.
|
||||
#
|
||||
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
|
||||
# which have later been changed to m4_define as they aren't part of the
|
||||
# exported API, or moved to Autoconf or Automake where they belong.
|
||||
#
|
||||
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
|
||||
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
|
||||
# using a macro with the same name in our local m4/libtool.m4 it'll
|
||||
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
|
||||
# and doesn't know about Autoconf macros at all.)
|
||||
#
|
||||
# So we provide this file, which has a silly filename so it's always
|
||||
# included after everything else. This provides aclocal with the
|
||||
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
|
||||
# because those macros already exist, or will be overwritten later.
|
||||
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
|
||||
#
|
||||
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
|
||||
# Yes, that means every name once taken will need to remain here until
|
||||
# we give up compatibility with versions before 1.7, at which point
|
||||
# we need to keep only those names which we still refer to.
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
|
||||
|
||||
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
|
||||
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
|
||||
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
|
||||
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
|
||||
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
|
||||
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
|
||||
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
|
||||
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
|
||||
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
|
||||
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
|
||||
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
|
||||
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
|
||||
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
|
||||
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
|
||||
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
|
||||
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
|
||||
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
|
||||
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
|
||||
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
|
||||
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
|
||||
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
|
||||
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
|
||||
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
|
||||
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
|
||||
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
|
||||
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
|
||||
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
|
||||
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
|
||||
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
|
||||
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
|
||||
m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
|
||||
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
|
|
@ -894,7 +894,7 @@
|
|||
],
|
||||
'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'],
|
||||
'msvs_disabled_warnings': [
|
||||
4091, 4100, 4127, 4366, 4396, 4503, 4512, 4819, 4995, 4702
|
||||
4100, 4127, 4396, 4503, 4512, 4819, 4995, 4702
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
|
|
|
@ -32,15 +32,15 @@
|
|||
'target_name': 'gtest',
|
||||
'type': 'static_library',
|
||||
'sources': [
|
||||
'../testing/googletest/src/gtest-all.cc',
|
||||
'../testing/gtest/src/gtest-all.cc',
|
||||
],
|
||||
'include_dirs': [
|
||||
'../testing/googletest',
|
||||
'../testing/googletest/include',
|
||||
'../testing/gtest',
|
||||
'../testing/gtest/include',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'../testing/googletest/include',
|
||||
'../testing/gtest/include',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
@ -51,7 +51,7 @@
|
|||
'gtest',
|
||||
],
|
||||
'sources': [
|
||||
'../testing/googletest/src/gtest_main.cc',
|
||||
'gtest/src/gtest_main.cc',
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -61,15 +61,15 @@
|
|||
'gtest',
|
||||
],
|
||||
'sources': [
|
||||
'../testing/googlemock/src/gmock-all.cc',
|
||||
'../testing/src/gmock-all.cc',
|
||||
],
|
||||
'include_dirs': [
|
||||
'../testing/googlemock',
|
||||
'../testing/googlemock/include',
|
||||
'../testing',
|
||||
'../testing/include',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'../testing/googlemock/include',
|
||||
'../testing/include',
|
||||
],
|
||||
},
|
||||
'export_dependent_settings': [
|
||||
|
@ -83,7 +83,7 @@
|
|||
'gmock',
|
||||
],
|
||||
'sources': [
|
||||
'../testing/googlemock/src/gmock_main.cc',
|
||||
'../testing/src/gmock_main.cc',
|
||||
],
|
||||
},
|
||||
],
|
|
@ -230,13 +230,16 @@ breakpad_getcontext:
|
|||
#elif defined(__mips__)
|
||||
|
||||
// This implementation is inspired by implementation of getcontext in glibc.
|
||||
#include <asm-mips/asm.h>
|
||||
#include <asm-mips/regdef.h>
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
#include <asm-mips/fpregdef.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/fpregdef.h>
|
||||
#else
|
||||
#include <machine/asm.h>
|
||||
#include <machine/regdef.h>
|
||||
#endif
|
||||
|
||||
// from asm-mips/asm.h
|
||||
// from asm/asm.h
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
#define ALSZ 7
|
||||
#define ALMASK ~7
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
# asm-mips
|
||||
|
||||
The files in this directory are almost direct copies from Android NDK r12, with
|
||||
the exception of changing the include guards to Breakpad ones. They are copied
|
||||
from the MIPS asm/ directory, but are meant to be used as replacements for both
|
||||
asm/ and machine/ includes since the files in each are largely duplicates.
|
||||
|
||||
Some MIPS asm/ and all machine/ headers were removed in the move to unified NDK
|
||||
headers, so Breakpad fails to compile on newer NDK versions without these files.
|
|
@ -1,270 +0,0 @@
|
|||
#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_ASM_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_ASM_H
|
||||
|
||||
#if defined(__has_include_next) && __has_include_next(<asm/asm.h>)
|
||||
#include_next <asm/asm.h>
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
****************************************************************************
|
||||
***
|
||||
*** This header was automatically generated from a Linux kernel header
|
||||
*** of the same name, to make information necessary for userspace to
|
||||
*** call into the kernel available to libc. It contains only constants,
|
||||
*** structures, and macros generated from the original header, and thus,
|
||||
*** contains no copyrightable information.
|
||||
***
|
||||
*** To edit the content of this header, modify the corresponding
|
||||
*** source file (e.g. under external/kernel-headers/original/) then
|
||||
*** run bionic/libc/kernel/tools/update_all.py
|
||||
***
|
||||
*** Any manual change here will be lost the next time this script will
|
||||
*** be run. You've been warned!
|
||||
***
|
||||
****************************************************************************
|
||||
****************************************************************************/
|
||||
|
||||
#include <asm/sgidefs.h>
|
||||
#ifndef CAT
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#ifdef __STDC__
|
||||
#define __CAT(str1, str2) str1##str2
|
||||
#else
|
||||
#define __CAT(str1, str2) str1 str2
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#define CAT(str1, str2) __CAT(str1, str2)
|
||||
#endif
|
||||
#ifdef __PIC__
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define CPRESTORE(register) .cprestore register
|
||||
#define CPADD(register) .cpadd register
|
||||
#define CPLOAD(register) .cpload register
|
||||
#else
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define CPRESTORE(register)
|
||||
#define CPADD(register)
|
||||
#define CPLOAD(register)
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LEAF(symbol) .globl symbol; .align 2; .type symbol, @function; .ent symbol, 0; symbol: .frame sp, 0, ra
|
||||
#define NESTED(symbol, framesize, rpc) .globl symbol; .align 2; .type symbol, @function; .ent symbol, 0; symbol: .frame sp, framesize, rpc
|
||||
#define END(function) .end function; .size function, .-function
|
||||
#define EXPORT(symbol) .globl symbol; symbol:
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define FEXPORT(symbol) .globl symbol; .type symbol, @function; symbol:
|
||||
#define ABS(symbol,value) .globl symbol; symbol = value
|
||||
#define PANIC(msg) .set push; .set reorder; PTR_LA a0, 8f; jal panic; 9: b 9b; .set pop; TEXT(msg)
|
||||
#define PRINT(string)
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define TEXT(msg) .pushsection .data; 8: .asciiz msg; .popsection;
|
||||
#define TTABLE(string) .pushsection .text; .word 1f; .popsection .pushsection .data; 1: .asciiz string; .popsection
|
||||
#define PREF(hint, addr)
|
||||
#define PREFX(hint, addr)
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#if _MIPS_ISA == _MIPS_ISA_MIPS1
|
||||
#define MOVN(rd, rs, rt) .set push; .set reorder; beqz rt, 9f; move rd, rs; .set pop; 9:
|
||||
#define MOVZ(rd, rs, rt) .set push; .set reorder; bnez rt, 9f; move rd, rs; .set pop; 9:
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#if _MIPS_ISA == _MIPS_ISA_MIPS2 || _MIPS_ISA == _MIPS_ISA_MIPS3
|
||||
#define MOVN(rd, rs, rt) .set push; .set noreorder; bnezl rt, 9f; move rd, rs; .set pop; 9:
|
||||
#define MOVZ(rd, rs, rt) .set push; .set noreorder; beqzl rt, 9f; move rd, rs; .set pop; 9:
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#if _MIPS_ISA == _MIPS_ISA_MIPS4 || _MIPS_ISA == _MIPS_ISA_MIPS5 || _MIPS_ISA == _MIPS_ISA_MIPS32 || _MIPS_ISA == _MIPS_ISA_MIPS64
|
||||
#define MOVN(rd, rs, rt) movn rd, rs, rt
|
||||
#define MOVZ(rd, rs, rt) movz rd, rs, rt
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
#define ALSZ 7
|
||||
#define ALMASK ~7
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#if _MIPS_SIM == _MIPS_SIM_NABI32 || _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
#define ALSZ 15
|
||||
#define ALMASK ~15
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#ifdef __mips64
|
||||
#define SZREG 8
|
||||
#else
|
||||
#define SZREG 4
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
#define REG_S sw
|
||||
#define REG_L lw
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define REG_SUBU subu
|
||||
#define REG_ADDU addu
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_NABI32 || _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define REG_S sd
|
||||
#define REG_L ld
|
||||
#define REG_SUBU dsubu
|
||||
#define REG_ADDU daddu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SZINT == 32
|
||||
#define INT_ADD add
|
||||
#define INT_ADDU addu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_ADDI addi
|
||||
#define INT_ADDIU addiu
|
||||
#define INT_SUB sub
|
||||
#define INT_SUBU subu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_L lw
|
||||
#define INT_S sw
|
||||
#define INT_SLL sll
|
||||
#define INT_SLLV sllv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_SRL srl
|
||||
#define INT_SRLV srlv
|
||||
#define INT_SRA sra
|
||||
#define INT_SRAV srav
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SZINT == 64
|
||||
#define INT_ADD dadd
|
||||
#define INT_ADDU daddu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_ADDI daddi
|
||||
#define INT_ADDIU daddiu
|
||||
#define INT_SUB dsub
|
||||
#define INT_SUBU dsubu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_L ld
|
||||
#define INT_S sd
|
||||
#define INT_SLL dsll
|
||||
#define INT_SLLV dsllv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_SRL dsrl
|
||||
#define INT_SRLV dsrlv
|
||||
#define INT_SRA dsra
|
||||
#define INT_SRAV dsrav
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SZLONG == 32
|
||||
#define LONG_ADD add
|
||||
#define LONG_ADDU addu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_ADDI addi
|
||||
#define LONG_ADDIU addiu
|
||||
#define LONG_SUB sub
|
||||
#define LONG_SUBU subu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_L lw
|
||||
#define LONG_S sw
|
||||
#define LONG_SLL sll
|
||||
#define LONG_SLLV sllv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_SRL srl
|
||||
#define LONG_SRLV srlv
|
||||
#define LONG_SRA sra
|
||||
#define LONG_SRAV srav
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG .word
|
||||
#define LONGSIZE 4
|
||||
#define LONGMASK 3
|
||||
#define LONGLOG 2
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SZLONG == 64
|
||||
#define LONG_ADD dadd
|
||||
#define LONG_ADDU daddu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_ADDI daddi
|
||||
#define LONG_ADDIU daddiu
|
||||
#define LONG_SUB dsub
|
||||
#define LONG_SUBU dsubu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_L ld
|
||||
#define LONG_S sd
|
||||
#define LONG_SLL dsll
|
||||
#define LONG_SLLV dsllv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_SRL dsrl
|
||||
#define LONG_SRLV dsrlv
|
||||
#define LONG_SRA dsra
|
||||
#define LONG_SRAV dsrav
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG .dword
|
||||
#define LONGSIZE 8
|
||||
#define LONGMASK 7
|
||||
#define LONGLOG 3
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SZPTR == 32
|
||||
#define PTR_ADD add
|
||||
#define PTR_ADDU addu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_ADDI addi
|
||||
#define PTR_ADDIU addiu
|
||||
#define PTR_SUB sub
|
||||
#define PTR_SUBU subu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_L lw
|
||||
#define PTR_S sw
|
||||
#define PTR_LA la
|
||||
#define PTR_LI li
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_SLL sll
|
||||
#define PTR_SLLV sllv
|
||||
#define PTR_SRL srl
|
||||
#define PTR_SRLV srlv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_SRA sra
|
||||
#define PTR_SRAV srav
|
||||
#define PTR_SCALESHIFT 2
|
||||
#define PTR .word
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTRSIZE 4
|
||||
#define PTRLOG 2
|
||||
#endif
|
||||
#if _MIPS_SZPTR == 64
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_ADD dadd
|
||||
#define PTR_ADDU daddu
|
||||
#define PTR_ADDI daddi
|
||||
#define PTR_ADDIU daddiu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_SUB dsub
|
||||
#define PTR_SUBU dsubu
|
||||
#define PTR_L ld
|
||||
#define PTR_S sd
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_LA dla
|
||||
#define PTR_LI dli
|
||||
#define PTR_SLL dsll
|
||||
#define PTR_SLLV dsllv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_SRL dsrl
|
||||
#define PTR_SRLV dsrlv
|
||||
#define PTR_SRA dsra
|
||||
#define PTR_SRAV dsrav
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_SCALESHIFT 3
|
||||
#define PTR .dword
|
||||
#define PTRSIZE 8
|
||||
#define PTRLOG 3
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
#define MFC0 mfc0
|
||||
#define MTC0 mtc0
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_NABI32 || _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
#define MFC0 dmfc0
|
||||
#define MTC0 dmtc0
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#define SSNOP sll zero, zero, 1
|
||||
#define R10KCBARRIER(addr)
|
||||
#endif // defined(__has_include_next) && __has_include_next(<asm/asm.h>)
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_ASM_H
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
|
@ -1,117 +0,0 @@
|
|||
#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_FPREGDEF_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_FPREGDEF_H
|
||||
|
||||
#if defined(__has_include_next) && __has_include_next(<asm/fpregdef.h>)
|
||||
#include_next <asm/fpregdef.h>
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
****************************************************************************
|
||||
***
|
||||
*** This header was automatically generated from a Linux kernel header
|
||||
*** of the same name, to make information necessary for userspace to
|
||||
*** call into the kernel available to libc. It contains only constants,
|
||||
*** structures, and macros generated from the original header, and thus,
|
||||
*** contains no copyrightable information.
|
||||
***
|
||||
*** To edit the content of this header, modify the corresponding
|
||||
*** source file (e.g. under external/kernel-headers/original/) then
|
||||
*** run bionic/libc/kernel/tools/update_all.py
|
||||
***
|
||||
*** Any manual change here will be lost the next time this script will
|
||||
*** be run. You've been warned!
|
||||
***
|
||||
****************************************************************************
|
||||
****************************************************************************/
|
||||
|
||||
#include <asm/sgidefs.h>
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fv0 $f0
|
||||
#define fv0f $f1
|
||||
#define fv1 $f2
|
||||
#define fv1f $f3
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fa0 $f12
|
||||
#define fa0f $f13
|
||||
#define fa1 $f14
|
||||
#define fa1f $f15
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft0 $f4
|
||||
#define ft0f $f5
|
||||
#define ft1 $f6
|
||||
#define ft1f $f7
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft2 $f8
|
||||
#define ft2f $f9
|
||||
#define ft3 $f10
|
||||
#define ft3f $f11
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft4 $f16
|
||||
#define ft4f $f17
|
||||
#define ft5 $f18
|
||||
#define ft5f $f19
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fs0 $f20
|
||||
#define fs0f $f21
|
||||
#define fs1 $f22
|
||||
#define fs1f $f23
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fs2 $f24
|
||||
#define fs2f $f25
|
||||
#define fs3 $f26
|
||||
#define fs3f $f27
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fs4 $f28
|
||||
#define fs4f $f29
|
||||
#define fs5 $f30
|
||||
#define fs5f $f31
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fcr31 $31
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
|
||||
#define fv0 $f0
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fv1 $f2
|
||||
#define fa0 $f12
|
||||
#define fa1 $f13
|
||||
#define fa2 $f14
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fa3 $f15
|
||||
#define fa4 $f16
|
||||
#define fa5 $f17
|
||||
#define fa6 $f18
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fa7 $f19
|
||||
#define ft0 $f4
|
||||
#define ft1 $f5
|
||||
#define ft2 $f6
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft3 $f7
|
||||
#define ft4 $f8
|
||||
#define ft5 $f9
|
||||
#define ft6 $f10
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft7 $f11
|
||||
#define ft8 $f20
|
||||
#define ft9 $f21
|
||||
#define ft10 $f22
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft11 $f23
|
||||
#define ft12 $f1
|
||||
#define ft13 $f3
|
||||
#define fs0 $f24
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fs1 $f25
|
||||
#define fs2 $f26
|
||||
#define fs3 $f27
|
||||
#define fs4 $f28
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fs5 $f29
|
||||
#define fs6 $f30
|
||||
#define fs7 $f31
|
||||
#define fcr31 $31
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#endif // defined(__has_include_next) && __has_include_next(<asm/fpregdef.h>)
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_FPREGDEF_H
|
|
@ -1,125 +0,0 @@
|
|||
#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_REGDEF_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_REGDEF_H
|
||||
|
||||
#if defined(__has_include_next) && __has_include_next(<asm/regdef.h>)
|
||||
#include_next <asm/regdef.h>
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
****************************************************************************
|
||||
***
|
||||
*** This header was automatically generated from a Linux kernel header
|
||||
*** of the same name, to make information necessary for userspace to
|
||||
*** call into the kernel available to libc. It contains only constants,
|
||||
*** structures, and macros generated from the original header, and thus,
|
||||
*** contains no copyrightable information.
|
||||
***
|
||||
*** To edit the content of this header, modify the corresponding
|
||||
*** source file (e.g. under external/kernel-headers/original/) then
|
||||
*** run bionic/libc/kernel/tools/update_all.py
|
||||
***
|
||||
*** Any manual change here will be lost the next time this script will
|
||||
*** be run. You've been warned!
|
||||
***
|
||||
****************************************************************************
|
||||
****************************************************************************/
|
||||
|
||||
#include <asm/sgidefs.h>
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define zero $0
|
||||
#define AT $1
|
||||
#define v0 $2
|
||||
#define v1 $3
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define a0 $4
|
||||
#define a1 $5
|
||||
#define a2 $6
|
||||
#define a3 $7
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define t0 $8
|
||||
#define t1 $9
|
||||
#define t2 $10
|
||||
#define t3 $11
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define t4 $12
|
||||
#define t5 $13
|
||||
#define t6 $14
|
||||
#define t7 $15
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s0 $16
|
||||
#define s1 $17
|
||||
#define s2 $18
|
||||
#define s3 $19
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s4 $20
|
||||
#define s5 $21
|
||||
#define s6 $22
|
||||
#define s7 $23
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define t8 $24
|
||||
#define t9 $25
|
||||
#define jp $25
|
||||
#define k0 $26
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define k1 $27
|
||||
#define gp $28
|
||||
#define sp $29
|
||||
#define fp $30
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s8 $30
|
||||
#define ra $31
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define zero $0
|
||||
#define AT $at
|
||||
#define v0 $2
|
||||
#define v1 $3
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define a0 $4
|
||||
#define a1 $5
|
||||
#define a2 $6
|
||||
#define a3 $7
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define a4 $8
|
||||
#define ta0 $8
|
||||
#define a5 $9
|
||||
#define ta1 $9
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define a6 $10
|
||||
#define ta2 $10
|
||||
#define a7 $11
|
||||
#define ta3 $11
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define t0 $12
|
||||
#define t1 $13
|
||||
#define t2 $14
|
||||
#define t3 $15
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s0 $16
|
||||
#define s1 $17
|
||||
#define s2 $18
|
||||
#define s3 $19
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s4 $20
|
||||
#define s5 $21
|
||||
#define s6 $22
|
||||
#define s7 $23
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define t8 $24
|
||||
#define t9 $25
|
||||
#define jp $25
|
||||
#define k0 $26
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define k1 $27
|
||||
#define gp $28
|
||||
#define sp $29
|
||||
#define fp $30
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s8 $30
|
||||
#define ra $31
|
||||
#endif
|
||||
#endif // defined(__has_include_next) && __has_include_next(<asm/regdef.h>)
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_REGDEF_H
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
|
@ -49,6 +49,7 @@
|
|||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#if defined(ANDROID) && ANDROID_VERSION <= 20
|
||||
struct r_debug {
|
||||
int r_version;
|
||||
struct link_map* r_map;
|
||||
|
@ -67,6 +68,7 @@ struct link_map {
|
|||
struct link_map* l_next;
|
||||
struct link_map* l_prev;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017, Google Inc.
|
||||
// Copyright (c) 2013, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
|
@ -27,18 +27,15 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_PATH_HELPER_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_PATH_HELPER_H
|
||||
#ifndef GOOGLE_BREAKPAD_ANDROID_INCLUDE_SGIDEFS_H
|
||||
#define GOOGLE_BREAKPAD_ANDROID_INCLUDE_SGIDEFS_H
|
||||
|
||||
#include <string>
|
||||
#ifdef __mips__
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
// Android doesn't contain sgidefs.h, but does have <asm/sgidefs.h> which
|
||||
// contains what we need.
|
||||
#include <asm/sgidefs.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
#endif // __mips__
|
||||
|
||||
string BaseName(const string& path);
|
||||
string DirName(const string& path);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_PATH_HELPER_H
|
||||
#endif // GOOGLE_BREAKPAD_ANDROID_INCLUDE_SGIDEFS_H
|
|
@ -38,10 +38,6 @@
|
|||
// TODO(primiano): remove these changes after Chromium has stably rolled to
|
||||
// an NDK with the appropriate fixes. https://crbug.com/358831
|
||||
|
||||
// With traditional headers, <sys/user.h> forgot to do this. Unified headers get
|
||||
// it right.
|
||||
#include <sys/types.h>
|
||||
|
||||
#include_next <sys/user.h>
|
||||
|
||||
#include <android/api-level.h>
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
'android/breakpad_getcontext.S',
|
||||
'android/include/elf.h',
|
||||
'android/include/link.h',
|
||||
'android/include/sgidefs.h',
|
||||
'android/include/stab.h',
|
||||
'android/include/sys/procfs.h',
|
||||
'android/include/sys/signal.h',
|
||||
|
@ -120,8 +121,6 @@
|
|||
'linux/safe_readlink.h',
|
||||
'linux/synth_elf.cc',
|
||||
'linux/synth_elf.h',
|
||||
'long_string_dictionary.cc',
|
||||
'long_string_dictionary.h',
|
||||
'mac/arch_utilities.cc',
|
||||
'mac/arch_utilities.h',
|
||||
'mac/bootstrap_compat.cc',
|
||||
|
@ -221,7 +220,6 @@
|
|||
'linux/tests/auto_testfile.h',
|
||||
'linux/tests/crash_generator.cc',
|
||||
'linux/tests/crash_generator.h',
|
||||
'long_string_dictionary_unittest.cc',
|
||||
'mac/macho_reader_unittest.cc',
|
||||
'memory_allocator_unittest.cc',
|
||||
'memory_range_unittest.cc',
|
||||
|
@ -240,9 +238,9 @@
|
|||
],
|
||||
'dependencies': [
|
||||
'common',
|
||||
'../build/testing.gyp:gmock_main',
|
||||
'../build/testing.gyp:gmock',
|
||||
'../build/testing.gyp:gtest',
|
||||
'../build/testing.gypi:gmock_main',
|
||||
'../build/testing.gypi:gmock',
|
||||
'../build/testing.gypi:gtest',
|
||||
],
|
||||
'libraries': [
|
||||
'-ldl',
|
||||
|
|
|
@ -46,9 +46,7 @@ CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor,
|
|||
unsigned return_address_register,
|
||||
uint8_t version,
|
||||
const string &augmentation,
|
||||
bool dwarf64,
|
||||
uint8_t address_size,
|
||||
uint8_t segment_size) {
|
||||
bool dwarf64) {
|
||||
assert(!entry_length_);
|
||||
entry_length_ = new PendingLength();
|
||||
in_fde_ = false;
|
||||
|
@ -65,10 +63,6 @@ CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor,
|
|||
}
|
||||
D8(version);
|
||||
AppendCString(augmentation);
|
||||
if (version >= 4) {
|
||||
D8(address_size);
|
||||
D8(segment_size);
|
||||
}
|
||||
ULEB128(code_alignment_factor);
|
||||
LEB128(data_alignment_factor);
|
||||
if (version == 1)
|
||||
|
|
|
@ -138,9 +138,7 @@ class CFISection: public Section {
|
|||
unsigned return_address_register,
|
||||
uint8_t version = 3,
|
||||
const string &augmentation = "",
|
||||
bool dwarf64 = false,
|
||||
uint8_t address_size = 8,
|
||||
uint8_t segment_size = 0);
|
||||
bool dwarf64 = false);
|
||||
|
||||
// Append a Frame Description Entry header to this section with the
|
||||
// given values. If dwarf64 is true, use the 64-bit DWARF initial
|
||||
|
|
|
@ -232,7 +232,7 @@ enum DwarfAttribute {
|
|||
DW_AT_call_column = 0x57,
|
||||
DW_AT_call_file = 0x58,
|
||||
DW_AT_call_line = 0x59,
|
||||
// DWARF 4
|
||||
// DWARF 4 values.
|
||||
DW_AT_linkage_name = 0x6e,
|
||||
// SGI/MIPS extensions.
|
||||
DW_AT_MIPS_fde = 0x2001,
|
||||
|
@ -501,7 +501,7 @@ enum DwarfOpcode {
|
|||
DW_OP_call_frame_cfa =0x9c,
|
||||
DW_OP_bit_piece =0x9d,
|
||||
DW_OP_lo_user =0xe0,
|
||||
DW_OP_hi_user =0xff,
|
||||
DW_OP_hi_user =0xff,
|
||||
// GNU extensions
|
||||
DW_OP_GNU_push_tls_address =0xe0,
|
||||
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
|
||||
|
@ -544,8 +544,6 @@ enum DwarfLanguage
|
|||
DW_LANG_ObjC_plus_plus =0x0011,
|
||||
DW_LANG_UPC =0x0012,
|
||||
DW_LANG_D =0x0013,
|
||||
DW_LANG_Rust =0x001c,
|
||||
DW_LANG_Swift =0x001e,
|
||||
// Implementation-defined language code range.
|
||||
DW_LANG_lo_user = 0x8000,
|
||||
DW_LANG_hi_user = 0xffff,
|
||||
|
@ -672,7 +670,7 @@ enum DwarfPointerEncoding
|
|||
// encoding (except DW_EH_PE_aligned), and indicates that the
|
||||
// encoded value represents the address at which the true address
|
||||
// is stored, not the true address itself.
|
||||
DW_EH_PE_indirect = 0x80
|
||||
DW_EH_PE_indirect = 0x80
|
||||
};
|
||||
|
||||
} // namespace dwarf2reader
|
||||
|
|
|
@ -942,13 +942,6 @@ void LineInfo::ReadHeader() {
|
|||
header_.min_insn_length = reader_->ReadOneByte(lineptr);
|
||||
lineptr += 1;
|
||||
|
||||
if (header_.version >= 4) {
|
||||
__attribute__((unused)) uint8 max_ops_per_insn =
|
||||
reader_->ReadOneByte(lineptr);
|
||||
++lineptr;
|
||||
assert(max_ops_per_insn == 1);
|
||||
}
|
||||
|
||||
header_.default_is_stmt = reader_->ReadOneByte(lineptr);
|
||||
lineptr += 1;
|
||||
|
||||
|
@ -1265,12 +1258,12 @@ class CallFrameInfo::Rule {
|
|||
public:
|
||||
virtual ~Rule() { }
|
||||
|
||||
// Tell HANDLER that, at ADDRESS in the program, REG can be recovered using
|
||||
// this rule. If REG is kCFARegister, then this rule describes how to compute
|
||||
// the canonical frame address. Return what the HANDLER member function
|
||||
// returned.
|
||||
// Tell HANDLER that, at ADDRESS in the program, REGISTER can be
|
||||
// recovered using this rule. If REGISTER is kCFARegister, then this rule
|
||||
// describes how to compute the canonical frame address. Return what the
|
||||
// HANDLER member function returned.
|
||||
virtual bool Handle(Handler *handler,
|
||||
uint64 address, int reg) const = 0;
|
||||
uint64 address, int register) const = 0;
|
||||
|
||||
// Equality on rules. We use these to decide which rules we need
|
||||
// to report after a DW_CFA_restore_state instruction.
|
||||
|
@ -2260,11 +2253,11 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
|||
cursor++;
|
||||
|
||||
// If we don't recognize the version, we can't parse any more fields of the
|
||||
// CIE. For DWARF CFI, we handle versions 1 through 4 (there was never a
|
||||
// version 2 of CFI data). For .eh_frame, we handle versions 1 and 4 as well;
|
||||
// CIE. For DWARF CFI, we handle versions 1 through 3 (there was never a
|
||||
// version 2 of CFI data). For .eh_frame, we handle versions 1 and 3 as well;
|
||||
// the difference between those versions seems to be the same as for
|
||||
// .debug_frame.
|
||||
if (cie->version < 1 || cie->version > 4) {
|
||||
if (cie->version < 1 || cie->version > 3) {
|
||||
reporter_->UnrecognizedVersion(cie->offset, cie->version);
|
||||
return false;
|
||||
}
|
||||
|
@ -2294,36 +2287,16 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
|||
}
|
||||
}
|
||||
|
||||
if (cie->version >= 4) {
|
||||
uint8_t address_size = *cursor++;
|
||||
if (address_size != 8) {
|
||||
// TODO(scottmg): Only supporting x64 for now.
|
||||
reporter_->UnexpectedAddressSize(cie->offset, address_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t segment_size = *cursor++;
|
||||
if (segment_size != 0) {
|
||||
// TODO(scottmg): Only supporting x64 for now.
|
||||
// I would have perhaps expected 4 here, but LLVM emits a 0, near
|
||||
// http://llvm.org/docs/doxygen/html/MCDwarf_8cpp_source.html#l00606. As
|
||||
// we are not using the value, only succeed for now if it's the expected
|
||||
// 0.
|
||||
reporter_->UnexpectedSegmentSize(cie->offset, segment_size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the code alignment factor.
|
||||
cie->code_alignment_factor = reader_->ReadUnsignedLEB128(cursor, &len);
|
||||
if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie);
|
||||
cursor += len;
|
||||
|
||||
|
||||
// Parse the data alignment factor.
|
||||
cie->data_alignment_factor = reader_->ReadSignedLEB128(cursor, &len);
|
||||
if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie);
|
||||
cursor += len;
|
||||
|
||||
|
||||
// Parse the return address register. This is a ubyte in version 1, and
|
||||
// a ULEB128 in version 3.
|
||||
if (cie->version == 1) {
|
||||
|
@ -2434,7 +2407,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CallFrameInfo::ReadFDEFields(FDE *fde) {
|
||||
const uint8_t *cursor = fde->fields;
|
||||
size_t size;
|
||||
|
@ -2675,22 +2648,6 @@ void CallFrameInfo::Reporter::BadCIEId(uint64 offset, uint64 cie_offset) {
|
|||
filename_.c_str(), offset, section_.c_str(), cie_offset);
|
||||
}
|
||||
|
||||
void CallFrameInfo::Reporter::UnexpectedAddressSize(uint64 offset,
|
||||
uint8_t address_size) {
|
||||
fprintf(stderr,
|
||||
"%s: CFI frame description entry at offset 0x%llx in '%s':"
|
||||
" CIE specifies unexpected address size: %d\n",
|
||||
filename_.c_str(), offset, section_.c_str(), address_size);
|
||||
}
|
||||
|
||||
void CallFrameInfo::Reporter::UnexpectedSegmentSize(uint64 offset,
|
||||
uint8_t segment_size) {
|
||||
fprintf(stderr,
|
||||
"%s: CFI frame description entry at offset 0x%llx in '%s':"
|
||||
" CIE specifies unexpected segment size: %d\n",
|
||||
filename_.c_str(), offset, section_.c_str(), segment_size);
|
||||
}
|
||||
|
||||
void CallFrameInfo::Reporter::UnrecognizedVersion(uint64 offset, int version) {
|
||||
fprintf(stderr,
|
||||
"%s: CFI frame description entry at offset 0x%llx in '%s':"
|
||||
|
|
|
@ -1227,14 +1227,6 @@ class CallFrameInfo::Reporter {
|
|||
// there is not a CIE.
|
||||
virtual void BadCIEId(uint64 offset, uint64 cie_offset);
|
||||
|
||||
// The FDE at OFFSET refers to a CIE with an address size we don't know how
|
||||
// to handle.
|
||||
virtual void UnexpectedAddressSize(uint64 offset, uint8_t address_size);
|
||||
|
||||
// The FDE at OFFSET refers to a CIE with an segment descriptor size we
|
||||
// don't know how to handle.
|
||||
virtual void UnexpectedSegmentSize(uint64 offset, uint8_t segment_size);
|
||||
|
||||
// The FDE at OFFSET refers to a CIE with version number VERSION,
|
||||
// which we don't recognize. We cannot parse DWARF CFI if it uses
|
||||
// a version number we don't recognize.
|
||||
|
|
|
@ -126,8 +126,6 @@ class MockCallFrameErrorReporter: public CallFrameInfo::Reporter {
|
|||
MOCK_METHOD1(EarlyEHTerminator, void(uint64));
|
||||
MOCK_METHOD2(CIEPointerOutOfRange, void(uint64, uint64));
|
||||
MOCK_METHOD2(BadCIEId, void(uint64, uint64));
|
||||
MOCK_METHOD2(UnexpectedAddressSize, void(uint64, uint8_t));
|
||||
MOCK_METHOD2(UnexpectedSegmentSize, void(uint64, uint8_t));
|
||||
MOCK_METHOD2(UnrecognizedVersion, void(uint64, int version));
|
||||
MOCK_METHOD2(UnrecognizedAugmentation, void(uint64, const string &));
|
||||
MOCK_METHOD2(InvalidPointerEncoding, void(uint64, uint8));
|
||||
|
@ -607,91 +605,6 @@ TEST_F(CFI, CIEVersion3ReturnColumn) {
|
|||
EXPECT_TRUE(parser.Start());
|
||||
}
|
||||
|
||||
TEST_F(CFI, CIEVersion4AdditionalFields) {
|
||||
CFISection section(kBigEndian, 4);
|
||||
Label cie;
|
||||
section
|
||||
.Mark(&cie)
|
||||
// CIE version 4 with expected address and segment size.
|
||||
.CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 4, "", true, 8, 0)
|
||||
.FinishEntry()
|
||||
// FDE, citing that CIE.
|
||||
.FDEHeader(cie, 0x86763f2b, 0x2a66dc23)
|
||||
.FinishEntry();
|
||||
|
||||
PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section);
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 4, "", 0x89))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(handler, End()).WillOnce(Return(true));
|
||||
}
|
||||
|
||||
string contents;
|
||||
EXPECT_TRUE(section.GetContents(&contents));
|
||||
ByteReader byte_reader(ENDIANNESS_BIG);
|
||||
byte_reader.SetAddressSize(4);
|
||||
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
|
||||
contents.size(),
|
||||
&byte_reader, &handler, &reporter);
|
||||
EXPECT_TRUE(parser.Start());
|
||||
}
|
||||
|
||||
TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedAddressSize) {
|
||||
CFISection section(kBigEndian, 4);
|
||||
Label cie;
|
||||
|
||||
section
|
||||
.Mark(&cie)
|
||||
// Unexpected address size.
|
||||
.CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 4, "", true, 3, 0)
|
||||
.FinishEntry()
|
||||
// FDE, citing that CIE.
|
||||
.FDEHeader(cie, 0x86763f2b, 0x2a66dc23)
|
||||
.FinishEntry();
|
||||
|
||||
PERHAPS_WRITE_DEBUG_FRAME_FILE("AdditionalFieldsUnexpectedAddress", section);
|
||||
|
||||
EXPECT_CALL(reporter, UnexpectedAddressSize(_, 3))
|
||||
.WillOnce(Return());
|
||||
|
||||
string contents;
|
||||
EXPECT_TRUE(section.GetContents(&contents));
|
||||
ByteReader byte_reader(ENDIANNESS_BIG);
|
||||
byte_reader.SetAddressSize(8);
|
||||
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
|
||||
contents.size(),
|
||||
&byte_reader, &handler, &reporter);
|
||||
EXPECT_FALSE(parser.Start());
|
||||
}
|
||||
|
||||
TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedSegmentSize) {
|
||||
CFISection section(kBigEndian, 4);
|
||||
Label cie;
|
||||
|
||||
section
|
||||
.Mark(&cie)
|
||||
.CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 4, "", true, 8, 7)
|
||||
.FinishEntry()
|
||||
.FDEHeader(cie, 0x7bf0fda0, 0xcbcd28d8)
|
||||
.FinishEntry();
|
||||
|
||||
PERHAPS_WRITE_DEBUG_FRAME_FILE("AdditionalFieldsUnexpectedSegment", section);
|
||||
|
||||
EXPECT_CALL(reporter, UnexpectedSegmentSize(_, 7))
|
||||
.WillOnce(Return());
|
||||
|
||||
string contents;
|
||||
EXPECT_TRUE(section.GetContents(&contents));
|
||||
ByteReader byte_reader(ENDIANNESS_BIG);
|
||||
byte_reader.SetAddressSize(8);
|
||||
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
|
||||
contents.size(),
|
||||
&byte_reader, &handler, &reporter);
|
||||
EXPECT_FALSE(parser.Start());
|
||||
}
|
||||
|
||||
struct CFIInsnFixture: public CFIFixture {
|
||||
CFIInsnFixture() : CFIFixture() {
|
||||
data_factor = 0xb6f;
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <vector>
|
||||
|
||||
#include "common/dwarf/types.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::pair;
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ void DwarfCFIToModule::Record(Module::Address address, int reg,
|
|||
|
||||
// Place the name in our global set of strings, and then use the string
|
||||
// from the set. Even though the assignment looks like a copy, all the
|
||||
// major string implementations use reference counting internally,
|
||||
// major std::string implementations use reference counting internally,
|
||||
// so the effect is to have all our data structures share copies of rules
|
||||
// whenever possible. Since register names are drawn from a
|
||||
// vector<string>, register names are already shared.
|
||||
|
|
|
@ -181,7 +181,7 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
|
|||
|
||||
// The names of the return address and canonical frame address. Putting
|
||||
// these here instead of using string literals allows us to share their
|
||||
// texts in reference-counted string implementations (all the
|
||||
// texts in reference-counted std::string implementations (all the
|
||||
// popular ones). Many, many rules cite these strings.
|
||||
string cfa_name_, ra_name_;
|
||||
|
||||
|
@ -189,7 +189,7 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
|
|||
// our data structures, insert it into this set, and then use the string
|
||||
// from the set.
|
||||
//
|
||||
// Because string uses reference counting internally, simply using
|
||||
// Because std::string uses reference counting internally, simply using
|
||||
// strings from this set, even if passed by value, assigned, or held
|
||||
// directly in structures and containers (map<string, ...>, for example),
|
||||
// causes those strings to share a single instance of each distinct piece
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
#include "common/dwarf_cu_to_module.h"
|
||||
|
||||
#include <assert.h>
|
||||
#if !defined(__ANDROID__)
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
@ -261,7 +264,7 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
|
|||
uint64 offset_;
|
||||
|
||||
// Place the name in the global set of strings. Even though this looks
|
||||
// like a copy, all the major string implementations use reference
|
||||
// like a copy, all the major std::string implementations use reference
|
||||
// counting internally, so the effect is to have all the data structures
|
||||
// share copies of strings whenever possible.
|
||||
// FIXME: Should this return something like a string_ref to avoid the
|
||||
|
@ -351,23 +354,22 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
|
|||
case dwarf2reader::DW_AT_name:
|
||||
name_attribute_ = AddStringToPool(data);
|
||||
break;
|
||||
case dwarf2reader::DW_AT_MIPS_linkage_name:
|
||||
case dwarf2reader::DW_AT_linkage_name: {
|
||||
string demangled;
|
||||
Language::DemangleResult result =
|
||||
cu_context_->language->DemangleName(data, &demangled);
|
||||
switch (result) {
|
||||
case Language::kDemangleSuccess:
|
||||
demangled_name_ = AddStringToPool(demangled);
|
||||
break;
|
||||
|
||||
case Language::kDemangleFailure:
|
||||
cu_context_->reporter->DemangleError(data);
|
||||
// fallthrough
|
||||
case Language::kDontDemangle:
|
||||
demangled_name_.clear();
|
||||
raw_name_ = AddStringToPool(data);
|
||||
break;
|
||||
case dwarf2reader::DW_AT_linkage_name:
|
||||
case dwarf2reader::DW_AT_MIPS_linkage_name: {
|
||||
char* demangled = NULL;
|
||||
int status = -1;
|
||||
#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle.
|
||||
demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, &status);
|
||||
#endif
|
||||
if (status != 0) {
|
||||
cu_context_->reporter->DemangleError(data, status);
|
||||
demangled_name_ = "";
|
||||
raw_name_ = AddStringToPool(data);
|
||||
break;
|
||||
}
|
||||
if (demangled) {
|
||||
demangled_name_ = AddStringToPool(demangled);
|
||||
free(reinterpret_cast<void*>(demangled));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -682,10 +684,11 @@ void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) {
|
|||
filename_.c_str(), offset);
|
||||
}
|
||||
|
||||
void DwarfCUToModule::WarningReporter::DemangleError(const string &input) {
|
||||
void DwarfCUToModule::WarningReporter::DemangleError(
|
||||
const string &input, int error) {
|
||||
CUHeading();
|
||||
fprintf(stderr, "%s: warning: failed to demangle %s\n",
|
||||
filename_.c_str(), input.c_str());
|
||||
fprintf(stderr, "%s: warning: failed to demangle %s with error %d\n",
|
||||
filename_.c_str(), input.c_str(), error);
|
||||
}
|
||||
|
||||
void DwarfCUToModule::WarningReporter::UnhandledInterCUReference(
|
||||
|
@ -766,7 +769,6 @@ dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler(
|
|||
case dwarf2reader::DW_TAG_class_type:
|
||||
case dwarf2reader::DW_TAG_structure_type:
|
||||
case dwarf2reader::DW_TAG_union_type:
|
||||
case dwarf2reader::DW_TAG_module:
|
||||
return new NamedScopeHandler(cu_context_.get(), child_context_.get(),
|
||||
offset);
|
||||
default:
|
||||
|
@ -780,14 +782,6 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
|
|||
cu_context_->language = Language::Java;
|
||||
break;
|
||||
|
||||
case dwarf2reader::DW_LANG_Swift:
|
||||
cu_context_->language = Language::Swift;
|
||||
break;
|
||||
|
||||
case dwarf2reader::DW_LANG_Rust:
|
||||
cu_context_->language = Language::Rust;
|
||||
break;
|
||||
|
||||
// DWARF has no generic language code for assembly language; this is
|
||||
// what the GNU toolchain uses.
|
||||
case dwarf2reader::DW_LANG_Mips_Assembler:
|
||||
|
|
|
@ -202,7 +202,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
|||
virtual void UnnamedFunction(uint64 offset);
|
||||
|
||||
// __cxa_demangle() failed to demangle INPUT.
|
||||
virtual void DemangleError(const string &input);
|
||||
virtual void DemangleError(const string &input, int error);
|
||||
|
||||
// The DW_FORM_ref_addr at OFFSET to TARGET was not handled because
|
||||
// FilePrivate did not retain the inter-CU specification data.
|
||||
|
|
|
@ -83,7 +83,7 @@ class MockWarningReporter: public DwarfCUToModule::WarningReporter {
|
|||
MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
|
||||
MOCK_METHOD1(UncoveredLine, void(const Module::Line &line));
|
||||
MOCK_METHOD1(UnnamedFunction, void(uint64 offset));
|
||||
MOCK_METHOD1(DemangleError, void(const string &input));
|
||||
MOCK_METHOD2(DemangleError, void(const string &input, int error));
|
||||
MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target));
|
||||
};
|
||||
|
||||
|
@ -1205,7 +1205,6 @@ TEST_F(Specifications, Function) {
|
|||
}
|
||||
|
||||
TEST_F(Specifications, MangledName) {
|
||||
// Language defaults to C++, so no need to set it here.
|
||||
PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
|
||||
|
||||
StartCU();
|
||||
|
@ -1222,53 +1221,6 @@ TEST_F(Specifications, MangledName) {
|
|||
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
|
||||
}
|
||||
|
||||
TEST_F(Specifications, MangledNameSwift) {
|
||||
// Swift mangled names should pass through untouched.
|
||||
SetLanguage(dwarf2reader::DW_LANG_Swift);
|
||||
PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
|
||||
StartCU();
|
||||
const string kName = "_TFC9swifttest5Shape17simpleDescriptionfS0_FT_Si";
|
||||
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
|
||||
dwarf2reader::DW_TAG_subprogram, "declaration-name",
|
||||
kName);
|
||||
DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
|
||||
0xcd3c51b946fb1eeeLL, "",
|
||||
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
|
||||
root_handler_.Finish();
|
||||
|
||||
TestFunctionCount(1);
|
||||
TestFunction(0, kName,
|
||||
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
|
||||
}
|
||||
|
||||
TEST_F(Specifications, MangledNameRust) {
|
||||
SetLanguage(dwarf2reader::DW_LANG_Rust);
|
||||
PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
|
||||
|
||||
StartCU();
|
||||
const string kName = "_ZN14rustc_demangle8demangle17h373defa94bffacdeE";
|
||||
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
|
||||
dwarf2reader::DW_TAG_subprogram, "declaration-name",
|
||||
kName);
|
||||
DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
|
||||
0xcd3c51b946fb1eeeLL, "",
|
||||
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
|
||||
root_handler_.Finish();
|
||||
|
||||
TestFunctionCount(1);
|
||||
TestFunction(0,
|
||||
#ifndef HAVE_RUST_DEMANGLE
|
||||
// Rust mangled names should pass through untouched if not
|
||||
// using rust-demangle.
|
||||
kName,
|
||||
#else
|
||||
// If rust-demangle is available this should be properly
|
||||
// demangled.
|
||||
"rustc_demangle::demangle",
|
||||
#endif
|
||||
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
|
||||
}
|
||||
|
||||
TEST_F(Specifications, MemberFunction) {
|
||||
PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691);
|
||||
|
||||
|
|
|
@ -34,70 +34,18 @@
|
|||
|
||||
#include "common/language.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_RUST_DEMANGLE)
|
||||
#include <rust_demangle.h>
|
||||
#endif
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace {
|
||||
|
||||
string MakeQualifiedNameWithSeparator(const string& parent_name,
|
||||
const char* separator,
|
||||
const string& name) {
|
||||
if (parent_name.empty()) {
|
||||
return name;
|
||||
}
|
||||
|
||||
return parent_name + separator + name;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// C++ language-specific operations.
|
||||
class CPPLanguage: public Language {
|
||||
public:
|
||||
CPPLanguage() {}
|
||||
|
||||
string MakeQualifiedName(const string &parent_name,
|
||||
const string &name) const {
|
||||
return MakeQualifiedNameWithSeparator(parent_name, "::", name);
|
||||
}
|
||||
|
||||
virtual DemangleResult DemangleName(const string& mangled,
|
||||
string* demangled) const {
|
||||
#if defined(__ANDROID__)
|
||||
// Android NDK doesn't provide abi::__cxa_demangle.
|
||||
demangled->clear();
|
||||
return kDontDemangle;
|
||||
#else
|
||||
int status;
|
||||
char* demangled_c =
|
||||
abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
|
||||
|
||||
DemangleResult result;
|
||||
if (status == 0) {
|
||||
result = kDemangleSuccess;
|
||||
demangled->assign(demangled_c);
|
||||
} else {
|
||||
result = kDemangleFailure;
|
||||
demangled->clear();
|
||||
}
|
||||
|
||||
if (demangled_c) {
|
||||
free(reinterpret_cast<void*>(demangled_c));
|
||||
}
|
||||
|
||||
return result;
|
||||
#endif
|
||||
if (parent_name.empty())
|
||||
return name;
|
||||
else
|
||||
return parent_name + "::" + name;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -106,79 +54,19 @@ CPPLanguage CPPLanguageSingleton;
|
|||
// Java language-specific operations.
|
||||
class JavaLanguage: public Language {
|
||||
public:
|
||||
JavaLanguage() {}
|
||||
|
||||
string MakeQualifiedName(const string &parent_name,
|
||||
const string &name) const {
|
||||
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
|
||||
if (parent_name.empty())
|
||||
return name;
|
||||
else
|
||||
return parent_name + "." + name;
|
||||
}
|
||||
};
|
||||
|
||||
JavaLanguage JavaLanguageSingleton;
|
||||
|
||||
// Swift language-specific operations.
|
||||
class SwiftLanguage: public Language {
|
||||
public:
|
||||
SwiftLanguage() {}
|
||||
|
||||
string MakeQualifiedName(const string &parent_name,
|
||||
const string &name) const {
|
||||
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
|
||||
}
|
||||
|
||||
virtual DemangleResult DemangleName(const string& mangled,
|
||||
string* demangled) const {
|
||||
// There is no programmatic interface to a Swift demangler. Pass through the
|
||||
// mangled form because it encodes more information than the qualified name
|
||||
// that would have been built by MakeQualifiedName(). The output can be
|
||||
// post-processed by xcrun swift-demangle to transform mangled Swift names
|
||||
// into something more readable.
|
||||
demangled->assign(mangled);
|
||||
return kDemangleSuccess;
|
||||
}
|
||||
};
|
||||
|
||||
SwiftLanguage SwiftLanguageSingleton;
|
||||
|
||||
// Rust language-specific operations.
|
||||
class RustLanguage: public Language {
|
||||
public:
|
||||
RustLanguage() {}
|
||||
|
||||
string MakeQualifiedName(const string &parent_name,
|
||||
const string &name) const {
|
||||
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
|
||||
}
|
||||
|
||||
virtual DemangleResult DemangleName(const string& mangled,
|
||||
string* demangled) const {
|
||||
// Rust names use GCC C++ name mangling, but demangling them with
|
||||
// abi_demangle doesn't produce stellar results due to them having
|
||||
// another layer of encoding.
|
||||
// If callers provide rustc-demangle, use that.
|
||||
#if defined(HAVE_RUST_DEMANGLE)
|
||||
char* rust_demangled = rust_demangle(mangled.c_str());
|
||||
if (rust_demangled == nullptr) {
|
||||
return kDemangleFailure;
|
||||
}
|
||||
demangled->assign(rust_demangled);
|
||||
free_rust_demangled_name(rust_demangled);
|
||||
#else
|
||||
// Otherwise, pass through the mangled name so callers can demangle
|
||||
// after the fact.
|
||||
demangled->assign(mangled);
|
||||
#endif
|
||||
return kDemangleSuccess;
|
||||
}
|
||||
};
|
||||
|
||||
RustLanguage RustLanguageSingleton;
|
||||
|
||||
// Assembler language-specific operations.
|
||||
class AssemblerLanguage: public Language {
|
||||
public:
|
||||
AssemblerLanguage() {}
|
||||
|
||||
bool HasFunctions() const { return false; }
|
||||
string MakeQualifiedName(const string &parent_name,
|
||||
const string &name) const {
|
||||
|
@ -190,8 +78,6 @@ AssemblerLanguage AssemblerLanguageSingleton;
|
|||
|
||||
const Language * const Language::CPlusPlus = &CPPLanguageSingleton;
|
||||
const Language * const Language::Java = &JavaLanguageSingleton;
|
||||
const Language * const Language::Swift = &SwiftLanguageSingleton;
|
||||
const Language * const Language::Rust = &RustLanguageSingleton;
|
||||
const Language * const Language::Assembler = &AssemblerLanguageSingleton;
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -77,26 +77,9 @@ class Language {
|
|||
virtual string MakeQualifiedName (const string &parent_name,
|
||||
const string &name) const = 0;
|
||||
|
||||
enum DemangleResult {
|
||||
// Demangling was not performed because it’s not appropriate to attempt.
|
||||
kDontDemangle = -1,
|
||||
|
||||
kDemangleSuccess,
|
||||
kDemangleFailure,
|
||||
};
|
||||
|
||||
// Wraps abi::__cxa_demangle() or similar for languages where appropriate.
|
||||
virtual DemangleResult DemangleName(const string& mangled,
|
||||
string* demangled) const {
|
||||
demangled->clear();
|
||||
return kDontDemangle;
|
||||
}
|
||||
|
||||
// Instances for specific languages.
|
||||
static const Language * const CPlusPlus,
|
||||
* const Java,
|
||||
* const Swift,
|
||||
* const Rust,
|
||||
* const Assembler;
|
||||
};
|
||||
|
||||
|
|
|
@ -67,7 +67,6 @@
|
|||
#include "common/linux/file_id.h"
|
||||
#include "common/memory_allocator.h"
|
||||
#include "common/module.h"
|
||||
#include "common/path_helper.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
#ifndef NO_STABS_SUPPORT
|
||||
#include "common/stabs_reader.h"
|
||||
|
@ -108,6 +107,15 @@ using google_breakpad::wasteful_vector;
|
|||
#define EM_AARCH64 183
|
||||
#endif
|
||||
|
||||
// Define SHT_ANDROID_REL and SHT_ANDROID_RELA if not defined by the host.
|
||||
// Sections with this type contain Android packed relocations.
|
||||
#ifndef SHT_ANDROID_REL
|
||||
#define SHT_ANDROID_REL (SHT_LOOS + 1)
|
||||
#endif
|
||||
#ifndef SHT_ANDROID_RELA
|
||||
#define SHT_ANDROID_RELA (SHT_LOOS + 2)
|
||||
#endif
|
||||
|
||||
//
|
||||
// FDWrapper
|
||||
//
|
||||
|
@ -654,6 +662,7 @@ bool LoadSymbols(const string& obj_file,
|
|||
typedef typename ElfClass::Addr Addr;
|
||||
typedef typename ElfClass::Phdr Phdr;
|
||||
typedef typename ElfClass::Shdr Shdr;
|
||||
typedef typename ElfClass::Word Word;
|
||||
|
||||
Addr loading_addr = GetLoadingAddress<ElfClass>(
|
||||
GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff),
|
||||
|
@ -661,6 +670,8 @@ bool LoadSymbols(const string& obj_file,
|
|||
module->SetLoadAddress(loading_addr);
|
||||
info->set_loading_addr(loading_addr, obj_file);
|
||||
|
||||
Word debug_section_type =
|
||||
elf_header->e_machine == EM_MIPS ? SHT_MIPS_DWARF : SHT_PROGBITS;
|
||||
const Shdr* sections =
|
||||
GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
|
||||
const Shdr* section_names = sections + elf_header->e_shstrndx;
|
||||
|
@ -670,6 +681,28 @@ bool LoadSymbols(const string& obj_file,
|
|||
bool found_debug_info_section = false;
|
||||
bool found_usable_info = false;
|
||||
|
||||
// Reject files that contain Android packed relocations. The pre-packed
|
||||
// version of the file should be symbolized; the packed version is only
|
||||
// intended for use on the target system.
|
||||
if (FindElfSectionByName<ElfClass>(".rel.dyn", SHT_ANDROID_REL,
|
||||
sections, names,
|
||||
names_end, elf_header->e_shnum)) {
|
||||
fprintf(stderr, "%s: file contains a \".rel.dyn\" section "
|
||||
"with type SHT_ANDROID_REL\n", obj_file.c_str());
|
||||
fprintf(stderr, "Files containing Android packed relocations "
|
||||
"may not be symbolized.\n");
|
||||
return false;
|
||||
}
|
||||
if (FindElfSectionByName<ElfClass>(".rela.dyn", SHT_ANDROID_RELA,
|
||||
sections, names,
|
||||
names_end, elf_header->e_shnum)) {
|
||||
fprintf(stderr, "%s: file contains a \".rela.dyn\" section "
|
||||
"with type SHT_ANDROID_RELA\n", obj_file.c_str());
|
||||
fprintf(stderr, "Files containing Android packed relocations "
|
||||
"may not be symbolized.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.symbol_data != ONLY_CFI) {
|
||||
#ifndef NO_STABS_SUPPORT
|
||||
// Look for STABS debugging information, and load it if present.
|
||||
|
@ -694,19 +727,9 @@ bool LoadSymbols(const string& obj_file,
|
|||
|
||||
// Look for DWARF debugging information, and load it if present.
|
||||
const Shdr* dwarf_section =
|
||||
FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS,
|
||||
FindElfSectionByName<ElfClass>(".debug_info", debug_section_type,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
|
||||
// .debug_info section type is SHT_PROGBITS for mips on pnacl toolchains,
|
||||
// but MIPS_DWARF for regular gnu toolchains, so both need to be checked
|
||||
if (elf_header->e_machine == EM_MIPS && !dwarf_section) {
|
||||
dwarf_section =
|
||||
FindElfSectionByName<ElfClass>(".debug_info", SHT_MIPS_DWARF,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
}
|
||||
|
||||
if (dwarf_section) {
|
||||
found_debug_info_section = true;
|
||||
found_usable_info = true;
|
||||
|
@ -781,19 +804,9 @@ bool LoadSymbols(const string& obj_file,
|
|||
// Dwarf Call Frame Information (CFI) is actually independent from
|
||||
// the other DWARF debugging information, and can be used alone.
|
||||
const Shdr* dwarf_cfi_section =
|
||||
FindElfSectionByName<ElfClass>(".debug_frame", SHT_PROGBITS,
|
||||
FindElfSectionByName<ElfClass>(".debug_frame", debug_section_type,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
|
||||
// .debug_frame section type is SHT_PROGBITS for mips on pnacl toolchains,
|
||||
// but MIPS_DWARF for regular gnu toolchains, so both need to be checked
|
||||
if (elf_header->e_machine == EM_MIPS && !dwarf_cfi_section) {
|
||||
dwarf_cfi_section =
|
||||
FindElfSectionByName<ElfClass>(".debug_frame", SHT_MIPS_DWARF,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
}
|
||||
|
||||
if (dwarf_cfi_section) {
|
||||
// Ignore the return value of this function; even without call frame
|
||||
// information, the other debugging information could be perfectly
|
||||
|
@ -922,6 +935,16 @@ const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) {
|
|||
}
|
||||
}
|
||||
|
||||
// Return the non-directory portion of FILENAME: the portion after the
|
||||
// last slash, or the whole filename if there are no slashes.
|
||||
string BaseFileName(const string &filename) {
|
||||
// Lots of copies! basename's behavior is less than ideal.
|
||||
char* c_filename = strdup(filename.c_str());
|
||||
string base = basename(c_filename);
|
||||
free(c_filename);
|
||||
return base;
|
||||
}
|
||||
|
||||
template<typename ElfClass>
|
||||
bool SanitizeDebugFile(const typename ElfClass::Ehdr* debug_elf_header,
|
||||
const string& debuglink_file,
|
||||
|
@ -972,7 +995,7 @@ bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header,
|
|||
return false;
|
||||
}
|
||||
|
||||
string name = google_breakpad::BaseName(obj_filename);
|
||||
string name = BaseFileName(obj_filename);
|
||||
string os = "Linux";
|
||||
// Add an extra "0" at the end. PDB files on Windows have an 'age'
|
||||
// number appended to the end of the file identifier; this isn't
|
||||
|
|
|
@ -78,12 +78,14 @@ void FindElfClassSection(const char *elf_base,
|
|||
template<typename ElfClass>
|
||||
void FindElfClassSegment(const char *elf_base,
|
||||
typename ElfClass::Word segment_type,
|
||||
wasteful_vector<ElfSegment> *segments) {
|
||||
const void **segment_start,
|
||||
size_t *segment_size) {
|
||||
typedef typename ElfClass::Ehdr Ehdr;
|
||||
typedef typename ElfClass::Phdr Phdr;
|
||||
|
||||
assert(elf_base);
|
||||
assert(segments);
|
||||
assert(segment_start);
|
||||
assert(segment_size);
|
||||
|
||||
assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0);
|
||||
|
||||
|
@ -95,10 +97,9 @@ void FindElfClassSegment(const char *elf_base,
|
|||
|
||||
for (int i = 0; i < elf_header->e_phnum; ++i) {
|
||||
if (phdrs[i].p_type == segment_type) {
|
||||
ElfSegment seg = {};
|
||||
seg.start = elf_base + phdrs[i].p_offset;
|
||||
seg.size = phdrs[i].p_filesz;
|
||||
segments->push_back(seg);
|
||||
*segment_start = elf_base + phdrs[i].p_offset;
|
||||
*segment_size = phdrs[i].p_filesz;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +122,8 @@ bool FindElfSection(const void *elf_mapped_base,
|
|||
const char *section_name,
|
||||
uint32_t section_type,
|
||||
const void **section_start,
|
||||
size_t *section_size) {
|
||||
size_t *section_size,
|
||||
int *elfclass) {
|
||||
assert(elf_mapped_base);
|
||||
assert(section_start);
|
||||
assert(section_size);
|
||||
|
@ -133,6 +135,10 @@ bool FindElfSection(const void *elf_mapped_base,
|
|||
return false;
|
||||
|
||||
int cls = ElfClass(elf_mapped_base);
|
||||
if (elfclass) {
|
||||
*elfclass = cls;
|
||||
}
|
||||
|
||||
const char* elf_base =
|
||||
static_cast<const char*>(elf_mapped_base);
|
||||
|
||||
|
@ -149,25 +155,37 @@ bool FindElfSection(const void *elf_mapped_base,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool FindElfSegments(const void* elf_mapped_base,
|
||||
uint32_t segment_type,
|
||||
wasteful_vector<ElfSegment>* segments) {
|
||||
bool FindElfSegment(const void *elf_mapped_base,
|
||||
uint32_t segment_type,
|
||||
const void **segment_start,
|
||||
size_t *segment_size,
|
||||
int *elfclass) {
|
||||
assert(elf_mapped_base);
|
||||
assert(segments);
|
||||
assert(segment_start);
|
||||
assert(segment_size);
|
||||
|
||||
*segment_start = NULL;
|
||||
*segment_size = 0;
|
||||
|
||||
if (!IsValidElf(elf_mapped_base))
|
||||
return false;
|
||||
|
||||
int cls = ElfClass(elf_mapped_base);
|
||||
if (elfclass) {
|
||||
*elfclass = cls;
|
||||
}
|
||||
|
||||
const char* elf_base =
|
||||
static_cast<const char*>(elf_mapped_base);
|
||||
|
||||
if (cls == ELFCLASS32) {
|
||||
FindElfClassSegment<ElfClass32>(elf_base, segment_type, segments);
|
||||
return true;
|
||||
FindElfClassSegment<ElfClass32>(elf_base, segment_type,
|
||||
segment_start, segment_size);
|
||||
return *segment_start != NULL;
|
||||
} else if (cls == ELFCLASS64) {
|
||||
FindElfClassSegment<ElfClass64>(elf_base, segment_type, segments);
|
||||
return true;
|
||||
FindElfClassSegment<ElfClass64>(elf_base, segment_type,
|
||||
segment_start, segment_size);
|
||||
return *segment_start != NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -37,8 +37,6 @@
|
|||
#include <link.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/memory_allocator.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Traits classes so consumers can write templatized code to deal
|
||||
|
@ -83,12 +81,14 @@ int ElfClass(const void* elf_base);
|
|||
// Attempt to find a section named |section_name| of type |section_type|
|
||||
// in the ELF binary data at |elf_mapped_base|. On success, returns true
|
||||
// and sets |*section_start| to point to the start of the section data,
|
||||
// and |*section_size| to the size of the section's data.
|
||||
// and |*section_size| to the size of the section's data. If |elfclass|
|
||||
// is not NULL, set |*elfclass| to the ELF file class.
|
||||
bool FindElfSection(const void *elf_mapped_base,
|
||||
const char *section_name,
|
||||
uint32_t section_type,
|
||||
const void **section_start,
|
||||
size_t *section_size);
|
||||
size_t *section_size,
|
||||
int *elfclass);
|
||||
|
||||
// Internal helper method, exposed for convenience for callers
|
||||
// that already have more info.
|
||||
|
@ -101,17 +101,16 @@ FindElfSectionByName(const char* name,
|
|||
const char* names_end,
|
||||
int nsection);
|
||||
|
||||
struct ElfSegment {
|
||||
const void* start;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
// Attempt to find all segments of type |segment_type| in the ELF
|
||||
// binary data at |elf_mapped_base|. On success, returns true and fills
|
||||
// |*segments| with a list of segments of the given type.
|
||||
bool FindElfSegments(const void* elf_mapped_base,
|
||||
uint32_t segment_type,
|
||||
wasteful_vector<ElfSegment>* segments);
|
||||
// Attempt to find the first segment of type |segment_type| in the ELF
|
||||
// binary data at |elf_mapped_base|. On success, returns true and sets
|
||||
// |*segment_start| to point to the start of the segment data, and
|
||||
// and |*segment_size| to the size of the segment's data. If |elfclass|
|
||||
// is not NULL, set |*elfclass| to the ELF file class.
|
||||
bool FindElfSegment(const void *elf_mapped_base,
|
||||
uint32_t segment_type,
|
||||
const void **segment_start,
|
||||
size_t *segment_size,
|
||||
int *elfclass);
|
||||
|
||||
// Convert an offset from an Elf header into a pointer to the mapped
|
||||
// address in the current process. Takes an extra template parameter
|
||||
|
|
|
@ -61,11 +61,10 @@ FileID::FileID(const char* path) : path_(path) {}
|
|||
// These functions are also used inside the crashed process, so be safe
|
||||
// and use the syscall/libc wrappers instead of direct syscalls or libc.
|
||||
|
||||
template<typename ElfClass>
|
||||
static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length,
|
||||
wasteful_vector<uint8_t>& identifier) {
|
||||
static_assert(sizeof(ElfClass32::Nhdr) == sizeof(ElfClass64::Nhdr),
|
||||
"Elf32_Nhdr and Elf64_Nhdr should be the same");
|
||||
typedef typename ElfClass32::Nhdr Nhdr;
|
||||
typedef typename ElfClass::Nhdr Nhdr;
|
||||
|
||||
const void* section_end = reinterpret_cast<const char*>(section) + length;
|
||||
const Nhdr* note_header = reinterpret_cast<const Nhdr*>(section);
|
||||
|
@ -95,22 +94,24 @@ static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length,
|
|||
// and copy it into |identifier|.
|
||||
static bool FindElfBuildIDNote(const void* elf_mapped_base,
|
||||
wasteful_vector<uint8_t>& identifier) {
|
||||
PageAllocator allocator;
|
||||
// lld normally creates 2 PT_NOTEs, gold normally creates 1.
|
||||
auto_wasteful_vector<ElfSegment, 2> segs(&allocator);
|
||||
if (FindElfSegments(elf_mapped_base, PT_NOTE, &segs)) {
|
||||
for (ElfSegment& seg : segs) {
|
||||
if (ElfClassBuildIDNoteIdentifier(seg.start, seg.size, identifier)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* note_section;
|
||||
size_t note_size;
|
||||
if (FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE,
|
||||
(const void**)¬e_section, ¬e_size)) {
|
||||
return ElfClassBuildIDNoteIdentifier(note_section, note_size, identifier);
|
||||
int elfclass;
|
||||
if ((!FindElfSegment(elf_mapped_base, PT_NOTE,
|
||||
(const void**)¬e_section, ¬e_size, &elfclass) ||
|
||||
note_size == 0) &&
|
||||
(!FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE,
|
||||
(const void**)¬e_section, ¬e_size, &elfclass) ||
|
||||
note_size == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elfclass == ELFCLASS32) {
|
||||
return ElfClassBuildIDNoteIdentifier<ElfClass32>(note_section, note_size,
|
||||
identifier);
|
||||
} else if (elfclass == ELFCLASS64) {
|
||||
return ElfClassBuildIDNoteIdentifier<ElfClass64>(note_section, note_size,
|
||||
identifier);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -125,7 +126,7 @@ static bool HashElfTextSection(const void* elf_mapped_base,
|
|||
void* text_section;
|
||||
size_t text_size;
|
||||
if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS,
|
||||
(const void**)&text_section, &text_size) ||
|
||||
(const void**)&text_section, &text_size, NULL) ||
|
||||
text_size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
|
||||
#include "common/linux/guid_creator.h"
|
||||
#include "common/memory_allocator.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
|
@ -71,16 +70,16 @@ class FileID {
|
|||
// Convert the |identifier| data to a string. The string will
|
||||
// be formatted as a UUID in all uppercase without dashes.
|
||||
// (e.g., 22F065BBFC9C49F780FE26A7CEBD7BCE).
|
||||
static string ConvertIdentifierToUUIDString(
|
||||
static std::string ConvertIdentifierToUUIDString(
|
||||
const wasteful_vector<uint8_t>& identifier);
|
||||
|
||||
// Convert the entire |identifier| data to a hex string.
|
||||
static string ConvertIdentifierToString(
|
||||
static std::string ConvertIdentifierToString(
|
||||
const wasteful_vector<uint8_t>& identifier);
|
||||
|
||||
private:
|
||||
// Storage for the path specified
|
||||
string path_;
|
||||
std::string path_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -278,40 +278,6 @@ TYPED_TEST(FileIDTest, BuildIDPH) {
|
|||
EXPECT_EQ(expected_identifier_string, identifier_string);
|
||||
}
|
||||
|
||||
TYPED_TEST(FileIDTest, BuildIDMultiplePH) {
|
||||
const uint8_t kExpectedIdentifierBytes[] =
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13};
|
||||
const string expected_identifier_string =
|
||||
this->get_file_id(kExpectedIdentifierBytes);
|
||||
|
||||
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section text(kLittleEndian);
|
||||
text.Append(4096, 0);
|
||||
elf.AddSection(".text", text, SHT_PROGBITS);
|
||||
Notes notes1(kLittleEndian);
|
||||
notes1.AddNote(0, "Linux",
|
||||
reinterpret_cast<const uint8_t *>("\0x42\0x02\0\0"), 4);
|
||||
Notes notes2(kLittleEndian);
|
||||
notes2.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
|
||||
sizeof(kExpectedIdentifierBytes));
|
||||
int note1_idx = elf.AddSection(".note1", notes1, SHT_NOTE);
|
||||
int note2_idx = elf.AddSection(".note2", notes2, SHT_NOTE);
|
||||
elf.AddSegment(note1_idx, note1_idx, PT_NOTE);
|
||||
elf.AddSegment(note2_idx, note2_idx, PT_NOTE);
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
id_vector identifier(this->make_vector());
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier));
|
||||
EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
|
||||
|
||||
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
|
||||
EXPECT_EQ(expected_identifier_string, identifier_string);
|
||||
}
|
||||
|
||||
// Test to make sure two files with different text sections produce
|
||||
// different hashes when not using a build id.
|
||||
TYPED_TEST(FileIDTest, UniqueHashes) {
|
||||
|
|
|
@ -27,26 +27,15 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
#include "common/linux/guid_creator.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(HAVE_SYS_RANDOM_H)
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
|
||||
//
|
||||
// GUIDGenerator
|
||||
//
|
||||
|
@ -72,101 +61,28 @@ class GUIDGenerator {
|
|||
}
|
||||
|
||||
static bool CreateGUID(GUID *guid) {
|
||||
#if defined(HAVE_ARC4RANDOM) // Android, BSD, ...
|
||||
CreateGuidFromArc4Random(guid);
|
||||
#else // Linux
|
||||
bool success = false;
|
||||
|
||||
#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM)
|
||||
success = CreateGUIDFromGetrandom(guid);
|
||||
#endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM
|
||||
if (!success) {
|
||||
success = CreateGUIDFromDevUrandom(guid);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
CreateGUIDFromRand(guid);
|
||||
success = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Put in the version according to RFC 4122.
|
||||
guid->data3 &= 0x0fff;
|
||||
guid->data3 |= 0x4000;
|
||||
|
||||
// Put in the variant according to RFC 4122.
|
||||
guid->data4[0] &= 0x3f;
|
||||
guid->data4[0] |= 0x80;
|
||||
|
||||
InitOnce();
|
||||
guid->data1 = random();
|
||||
guid->data2 = (uint16_t)(random());
|
||||
guid->data3 = (uint16_t)(random());
|
||||
UInt32ToBytes(&guid->data4[0], random());
|
||||
UInt32ToBytes(&guid->data4[4], random());
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef HAVE_ARC4RANDOM
|
||||
static void CreateGuidFromArc4Random(GUID *guid) {
|
||||
char *buf = reinterpret_cast<char *>(guid);
|
||||
|
||||
for (size_t i = 0; i < sizeof(GUID); i += sizeof(uint32_t)) {
|
||||
uint32_t random_data = arc4random();
|
||||
|
||||
memcpy(buf + i, &random_data, sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void InitOnce() {
|
||||
pthread_once(&once_control, &InitOnceImpl);
|
||||
}
|
||||
|
||||
static void InitOnceImpl() {
|
||||
// time(NULL) is a very poor seed, so lacking anything better mix an
|
||||
// address into it. We drop the four rightmost bits as they're likely to
|
||||
// be 0 on almost all architectures.
|
||||
srand(time(NULL) | ((uintptr_t)&once_control >> 4));
|
||||
srandom(time(NULL));
|
||||
}
|
||||
|
||||
static pthread_once_t once_control;
|
||||
|
||||
#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM)
|
||||
static bool CreateGUIDFromGetrandom(GUID *guid) {
|
||||
char *buf = reinterpret_cast<char *>(guid);
|
||||
int read_bytes = getrandom(buf, sizeof(GUID), GRND_NONBLOCK);
|
||||
|
||||
return (read_bytes == static_cast<int>(sizeof(GUID)));
|
||||
}
|
||||
#endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM
|
||||
|
||||
// Populate the GUID using random bytes read from /dev/urandom, returns false
|
||||
// if the GUID wasn't fully populated with random data.
|
||||
static bool CreateGUIDFromDevUrandom(GUID *guid) {
|
||||
char *buf = reinterpret_cast<char *>(guid);
|
||||
int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
|
||||
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t read_bytes = HANDLE_EINTR(read(fd, buf, sizeof(GUID)));
|
||||
close(fd);
|
||||
|
||||
return (read_bytes == static_cast<ssize_t>(sizeof(GUID)));
|
||||
}
|
||||
|
||||
// Populate the GUID using a stream of random bytes obtained from rand().
|
||||
static void CreateGUIDFromRand(GUID *guid) {
|
||||
char *buf = reinterpret_cast<char *>(guid);
|
||||
|
||||
InitOnce();
|
||||
|
||||
for (size_t i = 0; i < sizeof(GUID); i++) {
|
||||
buf[i] = rand();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
pthread_once_t GUIDGenerator::once_control = PTHREAD_ONCE_INIT;
|
||||
#endif
|
||||
|
||||
bool CreateGUID(GUID *guid) {
|
||||
return GUIDGenerator::CreateGUID(guid);
|
||||
|
|
|
@ -202,7 +202,7 @@ bool CrashGenerator::CreateChildCrash(
|
|||
// On Android the signal sometimes doesn't seem to get sent even though
|
||||
// tkill returns '0'. Retry a couple of times if the signal doesn't get
|
||||
// through on the first go:
|
||||
// https://bugs.chromium.org/p/google-breakpad/issues/detail?id=579
|
||||
// https://code.google.com/p/google-breakpad/issues/detail?id=579
|
||||
#if defined(__ANDROID__)
|
||||
const int kRetries = 60;
|
||||
const unsigned int kSleepTimeInSeconds = 1;
|
||||
|
|
|
@ -1,178 +0,0 @@
|
|||
// Copyright (c) 2017, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "common/long_string_dictionary.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "common/simple_string_dictionary.h"
|
||||
|
||||
#define arraysize(f) (sizeof(f) / sizeof(*f))
|
||||
|
||||
namespace {
|
||||
// Suffixes for segment keys.
|
||||
const char* const kSuffixes[] = {"__1", "__2", "__3", "__4", "__5", "__6",
|
||||
"__7", "__8", "__9", "__10"};
|
||||
#if !defined(NDEBUG)
|
||||
// The maximum suffix string length.
|
||||
const size_t kMaxSuffixLength = 4;
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::string;
|
||||
|
||||
void LongStringDictionary::SetKeyValue(const char* key, const char* value) {
|
||||
assert(key);
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
RemoveKey(key);
|
||||
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Key must not be an empty string.
|
||||
assert(key[0] != '\0');
|
||||
if (key[0] == '\0')
|
||||
return;
|
||||
|
||||
// If the value is not valid for segmentation, forwards the key and the value
|
||||
// to SetKeyValue of SimpleStringDictionary and returns.
|
||||
size_t value_length = strlen(value);
|
||||
if (value_length <= (value_size - 1)) {
|
||||
SimpleStringDictionary::SetKeyValue(key, value);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t key_length = strlen(key);
|
||||
assert(key_length + kMaxSuffixLength <= (key_size - 1));
|
||||
|
||||
char segment_key[key_size];
|
||||
char segment_value[value_size];
|
||||
|
||||
strcpy(segment_key, key);
|
||||
|
||||
const char* remain_value = value;
|
||||
size_t remain_value_length = strlen(value);
|
||||
|
||||
for (unsigned long i = 0; i < arraysize(kSuffixes); i++) {
|
||||
if (remain_value_length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy(segment_key + key_length, kSuffixes[i]);
|
||||
|
||||
size_t segment_value_length =
|
||||
std::min(remain_value_length, value_size - 1);
|
||||
|
||||
strncpy(segment_value, remain_value, segment_value_length);
|
||||
segment_value[segment_value_length] = '\0';
|
||||
|
||||
remain_value += segment_value_length;
|
||||
remain_value_length -= segment_value_length;
|
||||
|
||||
SimpleStringDictionary::SetKeyValue(segment_key, segment_value);
|
||||
}
|
||||
}
|
||||
|
||||
bool LongStringDictionary::RemoveKey(const char* key) {
|
||||
assert(key);
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
if (SimpleStringDictionary::RemoveKey(key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t key_length = strlen(key);
|
||||
assert(key_length + kMaxSuffixLength <= (key_size - 1));
|
||||
|
||||
char segment_key[key_size];
|
||||
strcpy(segment_key, key);
|
||||
|
||||
unsigned long i = 0;
|
||||
for (; i < arraysize(kSuffixes); i++) {
|
||||
strcpy(segment_key + key_length, kSuffixes[i]);
|
||||
if (!SimpleStringDictionary::RemoveKey(segment_key)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i != 0;
|
||||
}
|
||||
|
||||
const string LongStringDictionary::GetValueForKey(const char* key) const {
|
||||
assert(key);
|
||||
if (!key)
|
||||
return "";
|
||||
|
||||
// Key must not be an empty string.
|
||||
assert(key[0] != '\0');
|
||||
if (key[0] == '\0')
|
||||
return "";
|
||||
|
||||
const char* value = SimpleStringDictionary::GetValueForKey(key);
|
||||
if (value)
|
||||
return string(value);
|
||||
|
||||
size_t key_length = strlen(key);
|
||||
assert(key_length + kMaxSuffixLength <= (key_size - 1));
|
||||
|
||||
bool found_segment = false;
|
||||
char segment_key[key_size];
|
||||
string return_value;
|
||||
|
||||
strcpy(segment_key, key);
|
||||
for (unsigned long i = 0; i < arraysize(kSuffixes); i++) {
|
||||
strcpy(segment_key + key_length, kSuffixes[i]);
|
||||
|
||||
const char* segment_value =
|
||||
SimpleStringDictionary::GetValueForKey(segment_key);
|
||||
|
||||
if (segment_value != NULL) {
|
||||
found_segment = true;
|
||||
return_value.append(segment_value);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_segment) {
|
||||
return return_value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -1,87 +0,0 @@
|
|||
// Copyright (c) 2017, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef COMMON_LONG_STRING_DICTIONARY_H_
|
||||
#define COMMON_LONG_STRING_DICTIONARY_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/simple_string_dictionary.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
// key_size is the maxium size that |key| can take in
|
||||
// SimpleStringDictionary which is defined in simple_string_dictionary.h.
|
||||
//
|
||||
// value_size is the maxium size that |value| can take in
|
||||
// SimpleStringDictionary which is defined in simple_string_dictionary.h.
|
||||
//
|
||||
// LongStringDictionary is a subclass of SimpleStringDictionary which supports
|
||||
// longer values to be stored in the dictionary. The maximum length supported is
|
||||
// (value_size - 1) * 10.
|
||||
//
|
||||
// For example, LongStringDictionary will store long value with key 'abc' into
|
||||
// segment values with segment keys 'abc__1', 'abc__2', 'abc__3', ...
|
||||
//
|
||||
// Clients must avoid using the same suffixes as their key's suffix when
|
||||
// LongStringDictionary is used.
|
||||
class LongStringDictionary : public SimpleStringDictionary {
|
||||
public:
|
||||
// Stores |value| into |key|, or segment values into segment keys. The maxium
|
||||
// number of segments is 10. If |value| can not be stored in 10 segments, it
|
||||
// will be truncated. Replacing the existing value if |key| is already present
|
||||
// and replacing the existing segment values if segment keys are already
|
||||
// present.
|
||||
//
|
||||
// |key| must not be NULL. If the |value| need to be divided into segments,
|
||||
// the lengh of |key| must be smaller enough so that lengths of segment keys
|
||||
// which are key with suffixes are all samller than (key_size - 1). Currently,
|
||||
// the max length of suffixes are 4.
|
||||
//
|
||||
// If |value| is NULL, the key and its corresponding segment keys are removed
|
||||
// from the map. If there is no more space in the map, then the operation
|
||||
// silently fails.
|
||||
void SetKeyValue(const char* key, const char* value);
|
||||
|
||||
// Given |key|, removes any associated value or associated segment values.
|
||||
// |key| must not be NULL. If the key is not found, searchs its segment keys
|
||||
// and removes corresponding segment values if found.
|
||||
bool RemoveKey(const char* key);
|
||||
|
||||
// Given |key|, returns its corresponding |value|. |key| must not be NULL. If
|
||||
// the key is found, its corresponding |value| is returned.
|
||||
//
|
||||
// If no corresponding |value| is found, segment keys of the given |key| will
|
||||
// be used to search for corresponding segment values. If segment values
|
||||
// exist, assembled value from them is returned. If no segment value exists,
|
||||
// NULL is returned.
|
||||
const std::string GetValueForKey(const char* key) const;
|
||||
};
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LONG_STRING_DICTIONARY_H_
|
|
@ -1,301 +0,0 @@
|
|||
// Copyright (c) 2017, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/long_string_dictionary.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::string;
|
||||
|
||||
TEST(LongStringDictionary, LongStringDictionary) {
|
||||
// Make a new dictionary
|
||||
LongStringDictionary dict;
|
||||
|
||||
// Set three distinct values on three keys
|
||||
dict.SetKeyValue("key1", "value1");
|
||||
dict.SetKeyValue("key2", "value2");
|
||||
dict.SetKeyValue("key3", "value3");
|
||||
|
||||
EXPECT_EQ("value1", dict.GetValueForKey("key1"));
|
||||
EXPECT_EQ("value2", dict.GetValueForKey("key2"));
|
||||
EXPECT_EQ("value3", dict.GetValueForKey("key3"));
|
||||
EXPECT_EQ(3u, dict.GetCount());
|
||||
// try an unknown key
|
||||
EXPECT_EQ("", dict.GetValueForKey("key4"));
|
||||
|
||||
// Remove a key
|
||||
dict.RemoveKey("key3");
|
||||
|
||||
// Now make sure it's not there anymore
|
||||
EXPECT_EQ("", dict.GetValueForKey("key3"));
|
||||
|
||||
// Remove by setting value to NULL
|
||||
dict.SetKeyValue("key2", NULL);
|
||||
|
||||
// Now make sure it's not there anymore
|
||||
EXPECT_EQ("", dict.GetValueForKey("key2"));
|
||||
}
|
||||
|
||||
// Add a bunch of values to the dictionary, remove some entries in the middle,
|
||||
// and then add more.
|
||||
TEST(LongStringDictionary, Iterator) {
|
||||
LongStringDictionary* dict = new LongStringDictionary();
|
||||
ASSERT_TRUE(dict);
|
||||
|
||||
char key[LongStringDictionary::key_size];
|
||||
char value[LongStringDictionary::value_size];
|
||||
|
||||
const int kDictionaryCapacity = LongStringDictionary::num_entries;
|
||||
const int kPartitionIndex = kDictionaryCapacity - 5;
|
||||
|
||||
// We assume at least this size in the tests below
|
||||
ASSERT_GE(kDictionaryCapacity, 64);
|
||||
|
||||
// We'll keep track of the number of key/value pairs we think should
|
||||
// be in the dictionary
|
||||
int expectedDictionarySize = 0;
|
||||
|
||||
// Set a bunch of key/value pairs like key0/value0, key1/value1, ...
|
||||
for (int i = 0; i < kPartitionIndex; ++i) {
|
||||
sprintf(key, "key%d", i);
|
||||
sprintf(value, "value%d", i);
|
||||
dict->SetKeyValue(key, value);
|
||||
}
|
||||
expectedDictionarySize = kPartitionIndex;
|
||||
|
||||
// set a couple of the keys twice (with the same value) - should be nop
|
||||
dict->SetKeyValue("key2", "value2");
|
||||
dict->SetKeyValue("key4", "value4");
|
||||
dict->SetKeyValue("key15", "value15");
|
||||
|
||||
// Remove some random elements in the middle
|
||||
dict->RemoveKey("key7");
|
||||
dict->RemoveKey("key18");
|
||||
dict->RemoveKey("key23");
|
||||
dict->RemoveKey("key31");
|
||||
expectedDictionarySize -= 4; // we just removed four key/value pairs
|
||||
|
||||
// Set some more key/value pairs like key59/value59, key60/value60, ...
|
||||
for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) {
|
||||
sprintf(key, "key%d", i);
|
||||
sprintf(value, "value%d", i);
|
||||
dict->SetKeyValue(key, value);
|
||||
}
|
||||
expectedDictionarySize += kDictionaryCapacity - kPartitionIndex;
|
||||
|
||||
// Now create an iterator on the dictionary
|
||||
SimpleStringDictionary::Iterator iter(*dict);
|
||||
|
||||
// We then verify that it iterates through exactly the number of
|
||||
// key/value pairs we expect, and that they match one-for-one with what we
|
||||
// would expect. The ordering of the iteration does not matter...
|
||||
|
||||
// used to keep track of number of occurrences found for key/value pairs
|
||||
int count[kDictionaryCapacity];
|
||||
memset(count, 0, sizeof(count));
|
||||
|
||||
int totalCount = 0;
|
||||
|
||||
const SimpleStringDictionary::Entry* entry;
|
||||
while ((entry = iter.Next())) {
|
||||
totalCount++;
|
||||
|
||||
// Extract keyNumber from a string of the form key<keyNumber>
|
||||
int keyNumber;
|
||||
sscanf(entry->key, "key%d", &keyNumber);
|
||||
|
||||
// Extract valueNumber from a string of the form value<valueNumber>
|
||||
int valueNumber;
|
||||
sscanf(entry->value, "value%d", &valueNumber);
|
||||
|
||||
// The value number should equal the key number since that's how we set them
|
||||
EXPECT_EQ(keyNumber, valueNumber);
|
||||
|
||||
// Key and value numbers should be in proper range:
|
||||
// 0 <= keyNumber < kDictionaryCapacity
|
||||
bool isKeyInGoodRange = (keyNumber >= 0 && keyNumber < kDictionaryCapacity);
|
||||
bool isValueInGoodRange =
|
||||
(valueNumber >= 0 && valueNumber < kDictionaryCapacity);
|
||||
EXPECT_TRUE(isKeyInGoodRange);
|
||||
EXPECT_TRUE(isValueInGoodRange);
|
||||
|
||||
if (isKeyInGoodRange && isValueInGoodRange) {
|
||||
++count[keyNumber];
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure each of the key/value pairs showed up exactly one time, except
|
||||
// for the ones which we removed.
|
||||
for (size_t i = 0; i < kDictionaryCapacity; ++i) {
|
||||
// Skip over key7, key18, key23, and key31, since we removed them
|
||||
if (!(i == 7 || i == 18 || i == 23 || i == 31)) {
|
||||
EXPECT_EQ(count[i], 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the number of iterations matches the expected dictionary size.
|
||||
EXPECT_EQ(totalCount, expectedDictionarySize);
|
||||
}
|
||||
|
||||
TEST(LongStringDictionary, AddRemove) {
|
||||
LongStringDictionary dict;
|
||||
dict.SetKeyValue("rob", "ert");
|
||||
dict.SetKeyValue("mike", "pink");
|
||||
dict.SetKeyValue("mark", "allays");
|
||||
|
||||
EXPECT_EQ(3u, dict.GetCount());
|
||||
EXPECT_EQ("ert", dict.GetValueForKey("rob"));
|
||||
EXPECT_EQ("pink", dict.GetValueForKey("mike"));
|
||||
EXPECT_EQ("allays", dict.GetValueForKey("mark"));
|
||||
|
||||
dict.RemoveKey("mike");
|
||||
|
||||
EXPECT_EQ(2u, dict.GetCount());
|
||||
EXPECT_EQ("", dict.GetValueForKey("mike"));
|
||||
|
||||
dict.SetKeyValue("mark", "mal");
|
||||
EXPECT_EQ(2u, dict.GetCount());
|
||||
EXPECT_EQ("mal", dict.GetValueForKey("mark"));
|
||||
|
||||
dict.RemoveKey("mark");
|
||||
EXPECT_EQ(1u, dict.GetCount());
|
||||
EXPECT_EQ("", dict.GetValueForKey("mark"));
|
||||
}
|
||||
|
||||
TEST(LongStringDictionary, AddRemoveLongValue) {
|
||||
LongStringDictionary dict;
|
||||
|
||||
string long_value = string(256, 'x');
|
||||
dict.SetKeyValue("rob", long_value.c_str());
|
||||
|
||||
EXPECT_EQ(2u, dict.GetCount());
|
||||
|
||||
string long_value_part_1 = string(255, 'x');
|
||||
|
||||
EXPECT_EQ(long_value_part_1, dict.GetValueForKey("rob__1"));
|
||||
EXPECT_EQ("x", dict.GetValueForKey("rob__2"));
|
||||
|
||||
EXPECT_EQ(long_value, dict.GetValueForKey("rob"));
|
||||
|
||||
dict.RemoveKey("rob");
|
||||
EXPECT_EQ(0u, dict.GetCount());
|
||||
}
|
||||
|
||||
TEST(LongStringDictionary, AddRemoveSuperLongValue) {
|
||||
LongStringDictionary dict;
|
||||
|
||||
string long_value = string(255 * 10, 'x');
|
||||
dict.SetKeyValue("rob", long_value.c_str());
|
||||
|
||||
EXPECT_EQ(10u, dict.GetCount());
|
||||
|
||||
string long_value_part = string(255, 'x');
|
||||
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__1"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__2"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__3"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__4"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__5"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__6"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__7"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__8"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__9"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__10"));
|
||||
EXPECT_EQ(10u, dict.GetCount());
|
||||
|
||||
EXPECT_EQ(long_value, dict.GetValueForKey("rob"));
|
||||
|
||||
dict.RemoveKey("rob");
|
||||
EXPECT_EQ(0u, dict.GetCount());
|
||||
}
|
||||
|
||||
TEST(LongStringDictionary, TruncateSuperLongValue) {
|
||||
LongStringDictionary dict;
|
||||
|
||||
string long_value = string(255 * 11, 'x');
|
||||
dict.SetKeyValue("rob", long_value.c_str());
|
||||
|
||||
EXPECT_EQ(10u, dict.GetCount());
|
||||
|
||||
string long_value_part = string(255, 'x');
|
||||
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__1"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__2"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__3"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__4"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__5"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__6"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__7"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__8"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__9"));
|
||||
EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__10"));
|
||||
EXPECT_EQ(10u, dict.GetCount());
|
||||
|
||||
string expected_long_value = string(255 * 10, 'x');
|
||||
EXPECT_EQ(expected_long_value, dict.GetValueForKey("rob"));
|
||||
|
||||
dict.RemoveKey("rob");
|
||||
EXPECT_EQ(0u, dict.GetCount());
|
||||
}
|
||||
|
||||
TEST(LongStringDictionary, OverrideLongValue) {
|
||||
LongStringDictionary dict;
|
||||
|
||||
string long_value = string(255 * 10, 'x');
|
||||
dict.SetKeyValue("rob", long_value.c_str());
|
||||
|
||||
EXPECT_EQ(10u, dict.GetCount());
|
||||
EXPECT_EQ(long_value, dict.GetValueForKey("rob"));
|
||||
|
||||
dict.SetKeyValue("rob", "short_value");
|
||||
|
||||
EXPECT_EQ(1u, dict.GetCount());
|
||||
EXPECT_EQ("short_value", dict.GetValueForKey("rob"));
|
||||
}
|
||||
|
||||
TEST(LongStringDictionary, OverrideShortValue) {
|
||||
LongStringDictionary dict;
|
||||
|
||||
dict.SetKeyValue("rob", "short_value");
|
||||
|
||||
EXPECT_EQ(1u, dict.GetCount());
|
||||
EXPECT_EQ("short_value", dict.GetValueForKey("rob"));
|
||||
|
||||
string long_value = string(255 * 10, 'x');
|
||||
dict.SetKeyValue("rob", long_value.c_str());
|
||||
|
||||
EXPECT_EQ(10u, dict.GetCount());
|
||||
EXPECT_EQ(long_value, dict.GetValueForKey("rob"));
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -117,7 +117,7 @@
|
|||
// developer level errors. This implementation simply macros to NSLog/NSAssert.
|
||||
// It is not intended to be a general logging/reporting system.
|
||||
//
|
||||
// Please see https://github.com/google/google-toolbox-for-mac/wiki/DevLogNAssert
|
||||
// Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert
|
||||
// for a little more background on the usage of these macros.
|
||||
//
|
||||
// _GTMDevLog log some error/problem in debug builds
|
||||
|
|
|
@ -49,13 +49,13 @@ static NSString *PercentEncodeNSString(NSString *key) {
|
|||
|
||||
// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has
|
||||
// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements
|
||||
// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is
|
||||
// available on iOS 7+.
|
||||
// it using -[NSURLSession dataTaskWithRequest:completionHandler:] when using
|
||||
// those SDKs.
|
||||
static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
|
||||
NSURLResponse **out_response,
|
||||
NSError **out_error) {
|
||||
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
|
||||
__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \
|
||||
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \
|
||||
__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \
|
||||
(defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
|
||||
defined(MAC_OS_X_VERSION_10_11) && \
|
||||
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
|
||||
|
@ -223,7 +223,9 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
|
|||
|
||||
// Add any files to the message
|
||||
NSArray *fileNames = [files_ allKeys];
|
||||
for (NSString *name in fileNames) {
|
||||
count = [fileNames count];
|
||||
for (NSInteger i = 0; i < count; ++i) {
|
||||
NSString *name = [fileNames objectAtIndex:i];
|
||||
id fileOrData = [files_ objectForKey:name];
|
||||
NSData *fileData;
|
||||
|
||||
|
|
|
@ -111,7 +111,6 @@ namespace {
|
|||
enum Architecture {
|
||||
kArch_i386 = 0,
|
||||
kArch_x86_64,
|
||||
kArch_x86_64h,
|
||||
kArch_arm,
|
||||
kArch_arm64,
|
||||
kArch_ppc,
|
||||
|
@ -136,13 +135,6 @@ const NXArchInfo kKnownArchitectures[] = {
|
|||
NX_LittleEndian,
|
||||
"Intel x86-64"
|
||||
},
|
||||
{
|
||||
"x86_64h",
|
||||
CPU_TYPE_X86_64,
|
||||
CPU_SUBTYPE_X86_64_H,
|
||||
NX_LittleEndian,
|
||||
"Intel x86-64h Haswell"
|
||||
},
|
||||
{
|
||||
"arm",
|
||||
CPU_TYPE_ARM,
|
||||
|
@ -197,35 +189,23 @@ const NXArchInfo *NXGetArchInfoFromName(const char *name) {
|
|||
|
||||
const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype,
|
||||
cpu_subtype_t cpusubtype) {
|
||||
const NXArchInfo *candidate = NULL;
|
||||
for (int arch = 0; arch < kNumArchitectures; ++arch) {
|
||||
if (kKnownArchitectures[arch].cputype == cputype) {
|
||||
if (kKnownArchitectures[arch].cpusubtype == cpusubtype) {
|
||||
return &kKnownArchitectures[arch];
|
||||
}
|
||||
if (!candidate) {
|
||||
candidate = &kKnownArchitectures[arch];
|
||||
}
|
||||
return &kKnownArchitectures[arch];
|
||||
}
|
||||
}
|
||||
return candidate;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fat_arch *NXFindBestFatArch(cpu_type_t cputype,
|
||||
cpu_subtype_t cpusubtype,
|
||||
struct fat_arch *fat_archs,
|
||||
uint32_t nfat_archs) {
|
||||
struct fat_arch *candidate = NULL;
|
||||
for (uint32_t f = 0; f < nfat_archs; ++f) {
|
||||
if (fat_archs[f].cputype == cputype) {
|
||||
if (fat_archs[f].cpusubtype == cpusubtype) {
|
||||
return &fat_archs[f];
|
||||
}
|
||||
if (!candidate) {
|
||||
candidate = &fat_archs[f];
|
||||
}
|
||||
return &fat_archs[f];
|
||||
}
|
||||
}
|
||||
return candidate;
|
||||
return NULL;
|
||||
}
|
||||
#endif // !__APPLE__
|
||||
|
|
|
@ -31,13 +31,14 @@
|
|||
|
||||
// Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dump_syms.cc: Create a symbol file for use with minidumps
|
||||
// dump_syms.mm: Create a symbol file for use with minidumps
|
||||
|
||||
#include "common/mac/dump_syms.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <mach-o/arch.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <stdint.h>
|
||||
|
@ -59,7 +60,6 @@
|
|||
#include "common/mac/arch_utilities.h"
|
||||
#include "common/mac/macho_reader.h"
|
||||
#include "common/module.h"
|
||||
#include "common/path_helper.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "common/stabs_reader.h"
|
||||
#include "common/stabs_to_module.h"
|
||||
|
@ -370,7 +370,8 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
|
|||
}
|
||||
|
||||
// Compute a module name, to appear in the MODULE record.
|
||||
string module_name = google_breakpad::BaseName(object_filename_);
|
||||
string module_name = object_filename_;
|
||||
module_name = basename(&module_name[0]);
|
||||
|
||||
// Choose an identifier string, to appear in the MODULE record.
|
||||
string identifier = Identifier();
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче