summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdwarf/common/malloc_check.c
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2019-01-17 17:50:46 +0000
committerRobert Mustacchi <rm@joyent.com>2019-02-11 17:40:04 +0000
commitbc1f688b4872ace323eaddbb1a6365d054e7bf56 (patch)
tree3b6f2f4caaa4bafcfb4f757be7ea4de2858201ce /usr/src/lib/libdwarf/common/malloc_check.c
parent2b987d42b0ad07d74e39b18a2498709e5195d7e3 (diff)
downloadillumos-gate-bc1f688b4872ace323eaddbb1a6365d054e7bf56.tar.gz
6885 CTF Everywhere Part 1
6886 Want ctfdiff 6887 ctfdump should be written in terms of libctf 6888 ctfmerge should be implemented in terms of libctf 6889 ctfconvert should be implemented in terms of libctf 6890 Want general workq 6891 Want general mergeq 6892 ctf_add_encoded assigns() incorrect byte size to types 6893 ctf_add_{struct,union,enum} can reuse forwards 6894 ctf_add_{struct,union,enum} occasionally forget to dirty the ctf_file_t 6895 ctf_add_member could better handle bitfields 6896 ctf_type_size() reports wrong size for forwards 6897 Want libctf ctf_kind_name() function 6898 Want libctf function to set struct/union size Portions contributed by: John Levon <john.levon@joyent.com> Portions contributed by: Richard Lowe <richlowe@richlowe.net> Reviewed by: John Levon <john.levon@joyent.com> Reviewed by: Andy Fiddaman <andy@omniosce.org> Reviewed by: Gergő Doma <domag02@gmail.com> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/lib/libdwarf/common/malloc_check.c')
-rw-r--r--usr/src/lib/libdwarf/common/malloc_check.c339
1 files changed, 339 insertions, 0 deletions
diff --git a/usr/src/lib/libdwarf/common/malloc_check.c b/usr/src/lib/libdwarf/common/malloc_check.c
new file mode 100644
index 0000000000..1c6e7738e4
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/malloc_check.c
@@ -0,0 +1,339 @@
+/*
+
+ Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+/* malloc_check.c For checking dealloc completeness.
+
+ This code is as simple as possible and works ok for
+ reasonable size allocation counts.
+
+ It treats allocation as global, and so will not
+ work very well if an application opens more than one
+ Dwarf_Debug.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h> /* for exit() and various malloc
+ prototypes */
+#include "config.h"
+#include "dwarf_incl.h"
+#include "malloc_check.h"
+#ifdef WANT_LIBBDWARF_MALLOC_CHECK
+
+/* To turn off printing every entry, just change the define
+ to set PRINT_MALLOC_DETAILS 0.
+*/
+#define PRINT_MALLOC_DETAILS 0
+
+#define MC_TYPE_UNKNOWN 0
+#define MC_TYPE_ALLOC 1
+#define MC_TYPE_DEALLOC 2
+
+struct mc_data_s {
+ struct mc_data_s *mc_prev;
+ unsigned long mc_address; /* Assumes this is large enough to hold
+ a pointer! */
+
+ long mc_alloc_number; /* Assigned in order by when record
+ created. */
+ unsigned char mc_alloc_code; /* Allocation code, libdwarf. */
+ unsigned char mc_type;
+ unsigned char mc_dealloc_noted; /* Used on an ALLOC node. */
+ unsigned char mc_dealloc_noted_count; /* Used on an ALLOC
+ node. */
+};
+
+/*
+
+
+*/
+#define HASH_TABLE_SIZE 10501
+static struct mc_data_s *mc_data_hash[HASH_TABLE_SIZE];
+static long mc_data_list_size = 0;
+
+static char *alloc_type_name[MAX_DW_DLA + 1] = {
+ "",
+ "DW_DLA_STRING",
+ "DW_DLA_LOC",
+ "DW_DLA_LOCDESC",
+ "DW_DLA_ELLIST",
+ "DW_DLA_BOUNDS",
+ "DW_DLA_BLOCK",
+ "DW_DLA_DEBUG",
+ "DW_DLA_DIE",
+ "DW_DLA_LINE",
+ "DW_DLA_ATTR",
+ "DW_DLA_TYPE",
+ "DW_DLA_SUBSCR",
+ "DW_DLA_GLOBAL",
+ "DW_DLA_ERROR",
+ "DW_DLA_LIST",
+ "DW_DLA_LINEBUF",
+ "DW_DLA_ARANGE",
+ "DW_DLA_ABBREV",
+ "DW_DLA_FRAME_OP",
+ "DW_DLA_CIE",
+ "DW_DLA_FDE",
+ "DW_DLA_LOC_BLOCK",
+ "DW_DLA_FRAME_BLOCK",
+ "DW_DLA_FUNC",
+ "DW_DLA_TYPENAME",
+ "DW_DLA_VAR",
+ "DW_DLA_WEAK",
+ "DW_DLA_ADDR",
+ "DW_DLA_ABBREV_LIST",
+ "DW_DLA_CHAIN",
+ "DW_DLA_CU_CONTEXT",
+ "DW_DLA_FRAME",
+ "DW_DLA_GLOBAL_CONTEXT",
+ "DW_DLA_FILE_ENTRY",
+ "DW_DLA_LINE_CONTEXT",
+ "DW_DLA_LOC_CHAIN",
+ "DW_DLA_HASH_TABLE",
+ "DW_DLA_FUNC_CONTEXT",
+ "DW_DLA_TYPENAME_CONTEXT",
+ "DW_DLA_VAR_CONTEXT",
+ "DW_DLA_WEAK_CONTEXT",
+ "DW_DLA_PUBTYPES_CONTEXT"
+ /* Don't forget to expand this list if the list of codes
+ expands. */
+};
+
+static unsigned
+hash_address(unsigned long addr)
+{
+ unsigned long a = addr >> 2;
+
+ return a % HASH_TABLE_SIZE;
+}
+
+#if PRINT_MALLOC_DETAILS
+static void
+print_alloc_dealloc_detail(unsigned long addr,
+ int code, char *whichisit)
+{
+ fprintf(stderr,
+ "%s addr 0x%lx code %d (%s) entry %ld\n",
+ whichisit, addr, code, alloc_type_name[code],
+ mc_data_list_size);
+}
+#else
+#define print_alloc_dealloc_detail(a,b,c) /* nothing */
+#endif
+
+/* Create a zeroed struct or die. */
+static void *
+newone(void)
+{
+ struct mc_data_s *newd = malloc(sizeof(struct mc_data_s));
+
+ if (newd == 0) {
+ fprintf(stderr, "out of memory , # %ld\n", mc_data_list_size);
+ exit(1);
+ }
+ memset(newd, 0, sizeof(struct mc_data_s));
+ return newd;
+}
+
+/* Notify checker that get_alloc has allocated user data. */
+void
+dwarf_malloc_check_alloc_data(void *addr_in, unsigned char code)
+{
+ struct mc_data_s *newd = newone();
+ unsigned long addr = (unsigned long) addr_in;
+ struct mc_data_s **base = &mc_data_hash[hash_address(addr)];
+
+ print_alloc_dealloc_detail(addr, code, "alloc ");
+ newd->mc_address = addr;
+ newd->mc_alloc_code = code;
+ newd->mc_type = MC_TYPE_ALLOC;
+ newd->mc_alloc_number = mc_data_list_size;
+ newd->mc_prev = *base;
+ *base = newd;
+ newd->mc_alloc_number = mc_data_list_size;
+ mc_data_list_size += 1;
+}
+
+static void
+print_entry(char *msg, struct mc_data_s *data)
+{
+ fprintf(stderr,
+ "%s: 0x%08lx code %2d (%s) type %s dealloc noted %u ct %u\n",
+ msg,
+ (long) data->mc_address,
+ data->mc_alloc_code,
+ alloc_type_name[data->mc_alloc_code],
+ (data->mc_type == MC_TYPE_ALLOC) ? "alloc " :
+ (data->mc_type == MC_TYPE_DEALLOC) ? "dealloc" : "unknown",
+ (unsigned) data->mc_dealloc_noted,
+ (unsigned) data->mc_dealloc_noted_count);
+}
+
+/* newd is a 'dealloc'.
+*/
+static long
+balanced_by_alloc_p(struct mc_data_s *newd,
+ long *addr_match_num,
+ struct mc_data_s **addr_match,
+ struct mc_data_s *base)
+{
+ struct mc_data_s *cur = base;
+
+ for (; cur; cur = cur->mc_prev) {
+ if (cur->mc_address == newd->mc_address) {
+ if (cur->mc_type == MC_TYPE_ALLOC) {
+ if (cur->mc_alloc_code == newd->mc_alloc_code) {
+ *addr_match = cur;
+ *addr_match_num = cur->mc_alloc_number;
+ return cur->mc_alloc_number;
+ } else {
+ /* code mismatch */
+ *addr_match = cur;
+ *addr_match_num = cur->mc_alloc_number;
+ return -1;
+ }
+ } else {
+ /* Unbalanced new/del */
+ *addr_match = cur;
+ *addr_match_num = cur->mc_alloc_number;
+ return -1;
+ }
+ }
+ }
+ return -1;
+}
+
+/* A dealloc is to take place. Ensure it balances an alloc.
+*/
+void
+dwarf_malloc_check_dealloc_data(void *addr_in, unsigned char code)
+{
+ struct mc_data_s *newd = newone();
+ long prev;
+ long addr_match_num = -1;
+ struct mc_data_s *addr_match = 0;
+ unsigned long addr = (unsigned long) addr_in;
+ struct mc_data_s **base = &mc_data_hash[hash_address(addr)];
+
+
+ print_alloc_dealloc_detail(addr, code, "dealloc ");
+ newd->mc_address = (unsigned long) addr;
+ newd->mc_alloc_code = code;
+ newd->mc_type = MC_TYPE_DEALLOC;
+ newd->mc_prev = *base;
+ prev =
+ balanced_by_alloc_p(newd, &addr_match_num, &addr_match, *base);
+ if (prev < 0) {
+ fprintf(stderr,
+ "Unbalanced dealloc at index %ld\n", mc_data_list_size);
+ print_entry("new", newd);
+ fprintf(stderr, "addr-match_num? %ld\n", addr_match_num);
+ if (addr_match) {
+ print_entry("prev entry", addr_match);
+ if (addr_match->mc_dealloc_noted > 1) {
+ fprintf(stderr, "Above is Duplicate dealloc!\n");
+ }
+ }
+ abort();
+ exit(3);
+ }
+ addr_match->mc_dealloc_noted = 1;
+ addr_match->mc_dealloc_noted_count += 1;
+ if (addr_match->mc_dealloc_noted_count > 1) {
+ fprintf(stderr, "Double dealloc entry %ld\n", addr_match_num);
+ print_entry("new dealloc entry", newd);
+ print_entry("bad alloc entry", addr_match);
+ }
+ *base = newd;
+ mc_data_list_size += 1;
+}
+
+/* Final check for leaks.
+*/
+void
+dwarf_malloc_check_complete(char *msg)
+{
+ long i = 0;
+ long total = mc_data_list_size;
+ long hash_slots_used = 0;
+ long max_chain_length = 0;
+
+ fprintf(stderr, "Run complete, %s. %ld entries\n", msg, total);
+ for (; i < HASH_TABLE_SIZE; ++i) {
+ struct mc_data_s *cur = mc_data_hash[i];
+ long cur_chain_length = 0;
+
+ if (cur == 0)
+ continue;
+ ++hash_slots_used;
+ for (; cur; cur = cur->mc_prev) {
+ ++cur_chain_length;
+ if (cur->mc_type == MC_TYPE_ALLOC) {
+ if (cur->mc_dealloc_noted) {
+ if (cur->mc_dealloc_noted > 1) {
+ fprintf(stderr,
+ " Duplicate dealloc! entry %ld\n",
+ cur->mc_alloc_number);
+ print_entry("duplicate dealloc", cur);
+
+ }
+ continue;
+ } else {
+ fprintf(stderr, "malloc no dealloc, entry %ld\n",
+ cur->mc_alloc_number);
+ print_entry("dangle", cur);
+ }
+ } else {
+ /* mc_type is MC_TYPE_DEALLOC, already checked */
+
+ }
+ }
+ if (cur_chain_length > max_chain_length) {
+ max_chain_length = cur_chain_length;
+ }
+ }
+ fprintf(stderr, "mc hash table slots=%ld, "
+ "used=%ld, maxchain=%ld\n",
+ (long) HASH_TABLE_SIZE, hash_slots_used, max_chain_length);
+ return;
+}
+
+#else
+
+extern void *libdwarf_an_unused_function_so_not_empty_c_file();
+
+#endif /* WANT_LIBBDWARF_MALLOC_CHECK */