1 /* $OpenBSD: dump.c,v 1.12 2020/01/26 12:41:21 espie Exp $ */ 2 /* 3 * Copyright (c) 2012 Marc Espie. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD 18 * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 #include <limits.h> 27 #include <stddef.h> 28 #include <stdint.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <ohash.h> 33 #include "defines.h" 34 #include "gnode.h" 35 #include "dump.h" 36 #include "targ.h" 37 #include "var.h" 38 #include "memory.h" 39 #include "suff.h" 40 #include "lst.h" 41 #include "timestamp.h" 42 #include "dir.h" 43 44 /* since qsort doesn't have user data, this needs to be a global... */ 45 static ptrdiff_t cmp_offset; 46 static void targ_dump(bool); 47 48 static int 49 compare_names(const void *a, const void *b) 50 { 51 const char **pa = (const char **)a; 52 const char **pb = (const char **)b; 53 return strcmp((*pa) + cmp_offset, (*pb) + cmp_offset); 54 } 55 56 void * 57 sort_ohash_by_name(struct ohash *h) 58 { 59 cmp_offset = h->info.key_offset; 60 61 return sort_ohash(h, compare_names); 62 } 63 64 void * 65 sort_ohash(struct ohash *h, int (*comparison)(const void *, const void *)) 66 { 67 unsigned int i, j; 68 void *e; 69 size_t n = ohash_entries(h); 70 void **t = ereallocarray(NULL, n+1, sizeof(void *)); 71 cmp_offset = h->info.key_offset; 72 73 for (i = 0, e = ohash_first(h, &j); e != NULL; e = ohash_next(h, &j)) 74 t[i++] = e; 75 qsort(t, n, sizeof(void *), comparison); 76 /* add an extra entry to be able to figure out the end without needing 77 * to keep a counter */ 78 t[n] = NULL; 79 return t; 80 } 81 82 static void 83 TargPrintName(void *gnp) 84 { 85 const GNode *gn = gnp; 86 printf("%s ", gn->name); 87 } 88 89 static void 90 TargPrintOnlySrc(GNode *gn) 91 { 92 if (OP_NOP(gn->type) && gn->special == SPECIAL_NONE && 93 !(gn->type & OP_DUMMY)) { 94 if (gn->path != NULL) 95 printf("#\t%s [%s]\n", gn->name, 96 strcmp(gn->path, gn->name) == 0 ? "=" : gn->path); 97 else 98 printf("#\t%s\n", gn->name); 99 } 100 } 101 102 static void 103 TargPrintNode(GNode *gn, bool full) 104 { 105 if (OP_NOP(gn->type)) 106 return; 107 switch(gn->special) { 108 case SPECIAL_SUFFIXES: 109 case SPECIAL_PHONY: 110 case SPECIAL_ORDER: 111 case SPECIAL_NOTHING: 112 case SPECIAL_MAIN: 113 case SPECIAL_IGNORE: 114 return; 115 default: 116 break; 117 } 118 if (full) { 119 printf("# %d unmade prerequisites\n", gn->children_left); 120 if (! (gn->type & OP_USE)) { 121 if (!is_out_of_date(gn->mtime)) { 122 printf("# last modified %s: %s\n", 123 time_to_string(&gn->mtime), 124 status_to_string(gn)); 125 } else if (gn->built_status != UNKNOWN) { 126 printf("# non-existent (maybe): %s\n", 127 status_to_string(gn)); 128 } else { 129 printf("# unmade\n"); 130 } 131 } 132 } 133 if (!Lst_IsEmpty(&gn->parents)) { 134 printf("# parent targets: "); 135 Lst_Every(&gn->parents, TargPrintName); 136 fputc('\n', stdout); 137 } 138 if (gn->impliedsrc) 139 printf("# implied prerequisite: %s\n", gn->impliedsrc->name); 140 141 printf("%-16s", gn->name); 142 switch (gn->type & OP_OPMASK) { 143 case OP_DEPENDS: 144 printf(": "); break; 145 case OP_FORCE: 146 printf("! "); break; 147 case OP_DOUBLEDEP: 148 printf(":: "); break; 149 } 150 Targ_PrintType(gn->type); 151 Lst_Every(&gn->children, TargPrintName); 152 fputc('\n', stdout); 153 Lst_Every(&gn->commands, Targ_PrintCmd); 154 printf("\n\n"); 155 if (gn->type & OP_DOUBLEDEP) { 156 LstNode ln; 157 158 for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln)) 159 TargPrintNode(Lst_Datum(ln), full); 160 } 161 } 162 163 static void 164 dump_special(GNode **t, const char *name, int prop) 165 { 166 unsigned int i; 167 bool first = true; 168 169 for (i = 0; t[i] != NULL; i++) 170 if (t[i]->type & prop) { 171 if (first) { 172 printf("%s:", name); 173 first = false; 174 } 175 printf(" %s", t[i]->name); 176 } 177 if (!first) 178 printf("\n\n"); 179 } 180 181 static void 182 targ_dump(bool full) 183 { 184 GNode **t = sort_ohash_by_name(targets_hash()); 185 unsigned int i; 186 187 printf("# Input graph:\n"); 188 for (i = 0; t[i] != NULL; i++) 189 TargPrintNode(t[i], full); 190 printf("\n\n"); 191 192 dump_special(t, ".PHONY", OP_PHONY); 193 dump_special(t, ".PRECIOUS", OP_PRECIOUS); 194 dump_special(t, ".SILENT", OP_SILENT); 195 dump_special(t, ".IGNORE", OP_IGNORE); 196 printf("# Other target names:\n"); 197 for (i = 0; t[i] != NULL; i++) 198 TargPrintOnlySrc(t[i]); 199 printf("\n"); 200 free(t); 201 } 202 203 static bool dumped_once = false; 204 205 void 206 dump_data(void) 207 { 208 Var_Dump(); 209 Suff_PrintAll(); 210 targ_dump(false); 211 dumped_once = true; 212 } 213 214 void 215 post_mortem(void) 216 { 217 if (!dumped_once) { 218 Var_Dump(); 219 Suff_PrintAll(); 220 } 221 targ_dump(true); 222 } 223