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
compare_names(const void * a,const void * b)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 *
sort_ohash_by_name(struct ohash * h)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 *
sort_ohash(struct ohash * h,int (* comparison)(const void *,const 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
TargPrintName(void * gnp)83 TargPrintName(void *gnp)
84 {
85 const GNode *gn = gnp;
86 printf("%s ", gn->name);
87 }
88
89 static void
TargPrintOnlySrc(GNode * gn)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
TargPrintNode(GNode * gn,bool full)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
dump_special(GNode ** t,const char * name,int prop)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
targ_dump(bool full)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
dump_data(void)206 dump_data(void)
207 {
208 Var_Dump();
209 Suff_PrintAll();
210 targ_dump(false);
211 dumped_once = true;
212 }
213
214 void
post_mortem(void)215 post_mortem(void)
216 {
217 if (!dumped_once) {
218 Var_Dump();
219 Suff_PrintAll();
220 }
221 targ_dump(true);
222 }
223