[GFLAGS] Implement imagefile options
[reactos.git] / modules / rosapps / applications / cmdutils / gflags / imagefile.c
1 /*
2 * PROJECT: Global Flags utility
3 * LICENSE: GPL-2.0 (https://spdx.org/licenses/GPL-2.0)
4 * PURPOSE: Global Flags utility image file options
5 * COPYRIGHT: Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
6 */
7
8 #include "gflags.h"
9
10 static PWSTR ImageFile = NULL;
11 static DWORD OptionsAdd = 0;
12 static DWORD OptionsRemove = 0;
13 static BOOL OptionsSet = FALSE;
14
15 typedef struct FlagInfo
16 {
17 DWORD dwFlag;
18 const wchar_t* szAbbr;
19 WORD wDest;
20 const wchar_t* szDesc;
21 } FlagInfo;
22
23 #define FLG_DISABLE_DBGPRINT 0x8000000
24 #define FLG_CRITSEC_EVENT_CREATION 0x10000000
25 #define FLG_STOP_ON_UNHANDLED_EXCEPTION 0x20000000
26 #define FLG_ENABLE_HANDLE_EXCEPTIONS 0x40000000
27 #define FLG_DISABLE_PROTDLLS 0x80000000
28
29
30 static const FlagInfo g_Flags[] =
31 {
32 {FLG_STOP_ON_EXCEPTION, L"soe", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Stop on exception"},
33 {FLG_SHOW_LDR_SNAPS, L"sls", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Show loader snaps"},
34 {FLG_DEBUG_INITIAL_COMMAND, L"dic", (DEST_REGISTRY), L"Debug initial command"},
35 {FLG_STOP_ON_HUNG_GUI, L"shg", (DEST_KERNEL), L"Stop on hung GUI"},
36 {FLG_HEAP_ENABLE_TAIL_CHECK, L"htc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tail checking"},
37 {FLG_HEAP_ENABLE_FREE_CHECK, L"hfc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap free checking"},
38 {FLG_HEAP_VALIDATE_PARAMETERS, L"hpc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap parameter checking"},
39 {FLG_HEAP_VALIDATE_ALL, L"hvc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap validation on call"},
40 {FLG_APPLICATION_VERIFIER, L"vrf", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable application verifier"},
41 // FLG_MONITOR_SILENT_PROCESS_EXIT
42 {FLG_POOL_ENABLE_TAGGING, L"ptg", (DEST_REGISTRY), L"Enable pool tagging"},
43 {FLG_HEAP_ENABLE_TAGGING, L"htg", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tagging"},
44 {FLG_USER_STACK_TRACE_DB, L"ust", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Create user mode stack trace database"},
45 {FLG_KERNEL_STACK_TRACE_DB, L"kst", (DEST_REGISTRY), L"Create kernel mode stack trace database"},
46 {FLG_MAINTAIN_OBJECT_TYPELIST, L"otl", (DEST_REGISTRY), L"Maintain a list of objects for each type"},
47 {FLG_HEAP_ENABLE_TAG_BY_DLL, L"htd", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tagging by DLL"},
48 {FLG_DISABLE_STACK_EXTENSION, L"dse", (DEST_IMAGE), L"Disable stack extension"},
49
50 {FLG_ENABLE_CSRDEBUG, L"d32", (DEST_REGISTRY), L"Enable debugging of Win32 subsystem"},
51 {FLG_ENABLE_KDEBUG_SYMBOL_LOAD, L"ksl", (DEST_REGISTRY | DEST_KERNEL), L"Enable loading of kernel debugger symbols"},
52 {FLG_DISABLE_PAGE_KERNEL_STACKS, L"dps", (DEST_REGISTRY), L"Disable paging of kernel stacks"},
53 {FLG_ENABLE_SYSTEM_CRIT_BREAKS, L"scb", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable system critical breaks"},
54 {FLG_HEAP_DISABLE_COALESCING, L"dhc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Disable heap coalesce on free"},
55 {FLG_ENABLE_CLOSE_EXCEPTIONS, L"ece", (DEST_REGISTRY | DEST_KERNEL), L"Enable close exception"},
56 {FLG_ENABLE_EXCEPTION_LOGGING, L"eel", (DEST_REGISTRY | DEST_KERNEL), L"Enable exception logging"},
57 {FLG_ENABLE_HANDLE_TYPE_TAGGING, L"eot", (DEST_REGISTRY | DEST_KERNEL), L"Enable object handle type tagging"},
58 {FLG_HEAP_PAGE_ALLOCS, L"hpa", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable page heap"},
59 {FLG_DEBUG_INITIAL_COMMAND_EX, L"dwl", (DEST_REGISTRY), L"Debug WinLogon"},
60 {FLG_DISABLE_DBGPRINT, L"ddp", (DEST_REGISTRY | DEST_KERNEL), L"Buffer DbgPrint Output"},
61 {FLG_CRITSEC_EVENT_CREATION, L"cse", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Early critical section event creation"},
62 {FLG_STOP_ON_UNHANDLED_EXCEPTION, L"sue", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Stop on unhandled user-mode exception"},
63 {FLG_ENABLE_HANDLE_EXCEPTIONS, L"bhd", (DEST_REGISTRY | DEST_KERNEL), L"Enable bad handles detection"},
64 {FLG_DISABLE_PROTDLLS, L"dpd", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Disable protected DLL verification"},
65 };
66
67 void PrintFlags(IN DWORD GlobalFlags, IN OPTIONAL WORD Dest)
68 {
69 DWORD n;
70
71 for (n = 0; n < ARRAYSIZE(g_Flags); ++n)
72 {
73 if (!Dest || (g_Flags[n].wDest & Dest))
74 {
75 if (g_Flags[n].dwFlag & GlobalFlags)
76 {
77 wprintf(L" %s - %s\n", g_Flags[n].szAbbr, g_Flags[n].szDesc);
78 }
79 }
80 }
81 }
82
83 static void ShowStatus(DWORD GlobalFlags, DWORD Ignored)
84 {
85 if (GlobalFlags)
86 {
87 wprintf(L"Current Registry Settings for %s executable are: %08x\n", ImageFile, GlobalFlags);
88 PrintFlags(GlobalFlags, 0);
89 }
90 else
91 {
92 wprintf(L"No Registry Settings for %s executable\n", ImageFile);
93 }
94 if (Ignored)
95 {
96 wprintf(L"The following settings were ignored: %08x\n", Ignored);
97 PrintFlags(Ignored, 0);
98 }
99 }
100
101 static DWORD ValidateFlags(DWORD GlobalFlags, WORD Dest)
102 {
103 DWORD n;
104 DWORD Valid = 0;
105
106 for (n = 0; n < ARRAYSIZE(g_Flags); ++n)
107 {
108 if (g_Flags[n].wDest & Dest)
109 {
110 Valid |= g_Flags[n].dwFlag;
111 }
112 }
113
114 return GlobalFlags & Valid;
115 }
116
117 static DWORD FindFlag(PCWSTR Name, WORD Dest)
118 {
119 DWORD n;
120
121 for (n = 0; n < ARRAYSIZE(g_Flags); ++n)
122 {
123 if (g_Flags[n].wDest & Dest)
124 {
125 if (!wcsicmp(Name, g_Flags[n].szAbbr))
126 {
127 return g_Flags[n].dwFlag;
128 }
129 }
130 }
131
132 return 0;
133 }
134
135 static VOID ModifyStatus(VOID)
136 {
137 LONG Ret;
138 DWORD GlobalFlags, Requested, Ignored;
139 HKEY IFEOKey;
140 WCHAR Buffer[11];
141
142 if (!OpenImageFileExecOptions(KEY_WRITE | KEY_READ, ImageFile, &IFEOKey))
143 {
144 return;
145 }
146
147 if (OptionsSet)
148 {
149 Requested = OptionsAdd;
150 }
151 else
152 {
153 Requested = ReadSZFlagsFromRegistry(IFEOKey, L"GlobalFlag");
154 Requested &= ~OptionsRemove;
155 Requested |= OptionsAdd;
156 }
157
158 GlobalFlags = ValidateFlags(Requested, DEST_IMAGE);
159 Ignored = GlobalFlags ^ Requested;
160
161 if (GlobalFlags)
162 {
163 wsprintf(Buffer, L"0x%08x", GlobalFlags);
164 Ret = RegSetValueExW(IFEOKey, L"GlobalFlag", 0, REG_SZ, (BYTE*)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
165 if (Ret != ERROR_SUCCESS)
166 {
167 wprintf(L"MS: RegSetValueEx failed (%d)\n", Ret);
168 }
169 else
170 {
171 ShowStatus(GlobalFlags, Ignored);
172 }
173 }
174 else
175 {
176 Ret = RegDeleteValueW(IFEOKey, L"GlobalFlag");
177 if (Ret != ERROR_SUCCESS)
178 {
179 wprintf(L"MS: RegDeleteValue failed (%d)\n", Ret);
180 }
181 else
182 {
183 ShowStatus(GlobalFlags, Ignored);
184 }
185 }
186 CloseHandle(IFEOKey);
187 }
188
189
190 static VOID DisplayStatus(VOID)
191 {
192 HKEY IFEOKey;
193 DWORD GlobalFlags;
194
195 if (!OpenImageFileExecOptions(KEY_READ, ImageFile, &IFEOKey))
196 {
197 return;
198 }
199
200 GlobalFlags = ReadSZFlagsFromRegistry(IFEOKey, L"GlobalFlag");
201 ShowStatus(GlobalFlags, 0);
202
203 CloseHandle(IFEOKey);
204 }
205
206
207 BOOL ImageFile_ParseCmdline(INT i, int argc, LPWSTR argv[])
208 {
209 for (; i < argc; i++)
210 {
211 if (ImageFile == NULL)
212 {
213 ImageFile = argv[i];
214 }
215 else if (argv[i][0] == '+')
216 {
217 if (OptionsSet)
218 {
219 wprintf(L"Unexpected argument - '%s'\n", argv[i]);
220 return FALSE;
221 }
222 OptionsAdd |= FindFlag(argv[i] + 1, DEST_IMAGE);
223 }
224 else if (argv[i][0] == '-')
225 {
226 if (OptionsSet)
227 {
228 wprintf(L"Unexpected argument - '%s'\n", argv[i]);
229 return FALSE;
230 }
231 OptionsRemove |= FindFlag(argv[i] + 1, DEST_IMAGE);
232 }
233 else
234 {
235 OptionsSet = TRUE;
236 OptionsAdd = wcstoul(argv[i], NULL, 16);
237 if (OptionsAdd == ~0)
238 OptionsAdd = 0;
239 }
240 }
241
242 if (ImageFile == NULL)
243 {
244 wprintf(L"No Image specified\n");
245 return FALSE;
246 }
247
248 return TRUE;
249 }
250
251 INT ImageFile_Execute()
252 {
253 if (!OptionsAdd && !OptionsRemove && !OptionsSet)
254 {
255 DisplayStatus();
256 }
257 else
258 {
259 ModifyStatus();
260 }
261
262 return 0;
263 }