jcs's openbsd hax
openbsd
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... */
45static ptrdiff_t cmp_offset;
46static void targ_dump(bool);
47
48static int
49compare_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
56void *
57sort_ohash_by_name(struct ohash *h)
58{
59 cmp_offset = h->info.key_offset;
60
61 return sort_ohash(h, compare_names);
62}
63
64void *
65sort_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
82static void
83TargPrintName(void *gnp)
84{
85 const GNode *gn = gnp;
86 printf("%s ", gn->name);
87}
88
89static void
90TargPrintOnlySrc(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
102static void
103TargPrintNode(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
163static void
164dump_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
181static void
182targ_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
203static bool dumped_once = false;
204
205void
206dump_data(void)
207{
208 Var_Dump();
209 Suff_PrintAll();
210 targ_dump(false);
211 dumped_once = true;
212}
213
214void
215post_mortem(void)
216{
217 if (!dumped_once) {
218 Var_Dump();
219 Suff_PrintAll();
220 }
221 targ_dump(true);
222}