blob: 1571ada2236c7ff9f3d3c3906977262df23e2efc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define CDEV_CURRENT_FUNCTION _comment_
/**
* @file
* @ingroup Port
* @brief Dump formatting
*/
#undef CDEV_CURRENT_FUNCTION
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#if defined(LINUX)
#include <sys/mman.h>
#endif
#include "hyport.h"
#include <signal.h>
#define CDEV_CURRENT_FUNCTION _prototypes_private
static void markAllPagesWritable (struct HyPortLibrary *portLibrary);
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION appendCoreName
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hydump_create
/**
* Create a dump file of the OS state.
*
* @param[in] portLibrary The port library.
* @param[in] filename Buffer for filename optionally containing the filename where dump is to be output.
* @param[out] filename filename used for dump file or error message.
* @param[in] dumpType Type of dump to perform.
* @param[in] userData Implementation specific data.
*
* @return 0 on success, non-zero otherwise.
*
* @note filename buffer can not be NULL.
* @note user allocates and frees filename buffer.
* @note filename buffer length is platform dependent, assumed to be HyMaxPath/MAX_PATH
*
* @note if filename buffer is empty, a filename will be generated.
* @note if HYUNIQUE_DUMPS is set, filename will be unique.
*/
UDATA VMCALL
hydump_create (struct HyPortLibrary *portLibrary, char *filename,
char *dumpType, void *userData)
{
char *lastSep = filename ? strrchr (filename, DIR_SEPARATOR) : NULL;
IDATA pid;
/* dump a core file */
if ((pid = fork ()) == 0)
{
/* Move to specified folder before dumping? */
if (lastSep != NULL)
{
lastSep[1] = '\0';
if (0 != chdir (filename))
{
return -1;
}
}
/* Ensure we get default action (core) - reset primary&app handlers */
signal (SIGABRT, SIG_DFL);
#if defined(LINUX)
/* on Linux, shared library pages don't appear in core files by default. Mark
* all pages writable to force these pages to appear
*/
markAllPagesWritable (portLibrary);
#endif
abort ();
}
portLibrary->tty_err_printf (portLibrary,
"Note: dump may be truncated if \"ulimit -c\" is set too low\n");
/* guess typical filename */
if (lastSep != NULL)
{
lastSep[1] = '\0';
strcat (filename, "{default OS core name}");
}
else if (filename != NULL)
{
strcpy (filename, "{default OS core name}");
}
return 0;
}
#undef CDEV_CURRENT_FUNCTION
#if defined(LINUX)
#define CDEV_CURRENT_FUNCTION markAllPagesWritable
/**
* @internal read /proc/self/maps to determine what pages are mapped for this process.
* Modify each page to be writable. This will cause it to be included in core dumps.
*
* The format of /proc/self/maps is:
* 40000000-40013000 r-xp 00000000 03:03 1161002 /lib/ld-2.2.5.so
* 40013000-40014000 rw-p 00013000 03:03 1161002 /lib/ld-2.2.5.so
* 40014000-40016000 rw-p 00000000 00:00 0
* ...
*
* This implementation expects the format to be strictly conformed to.
* If deviations in the format are discovered, we'll have to make this routine
* more robust.
*/
static void
markAllPagesWritable (struct HyPortLibrary *portLibrary)
{
I_32 fd =
portLibrary->file_open (portLibrary, "/proc/self/maps", HyOpenRead, 0);
if (fd != -1)
{
/* sizeof(void*) * 2 is the number of hex digits to represent a pointer */
char buf[sizeof (void *) * 4 + sizeof ("-")];
while (portLibrary->
file_read (portLibrary, fd, buf,
sizeof (buf) - 1) == sizeof (buf) - 1)
{
char *next;
U_8 *start, *end;
int rc;
/* we've now read "40000000-40013000 " into buf */
/* NUL terminate buf for extra safety */
buf[sizeof (buf) - 1] = '\0';
/* use strtoull for correctness on 64-bit platforms and gratuitous extra precision on 32-bit platforms */
start = (U_8 *) (UDATA) strtoull (buf, &next, 16);
/* skip the '-' */
next += 1;
end = (U_8 *) (UDATA) strtoull (next, NULL, 16);
/* mark the pages as writable (and readable and executable, just in case they already were) */
rc =
mprotect (start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
/* skip to the next line */
while ((portLibrary->file_read (portLibrary, fd, buf, 1) == 1)
&& buf[0] != '\n');
}
portLibrary->file_close (portLibrary, fd);
}
}
#undef CDEV_CURRENT_FUNCTION
#endif
#define CDEV_CURRENT_FUNCTION
#undef CDEV_CURRENT_FUNCTION