]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c
ShellPkg/for: Fix potential null pointer deference
[mirror_edk2.git] / ShellPkg / Library / UefiShellDebug1CommandsLib / Comp.c
1 /** @file
2 Main file for Comp shell Debug1 function.
3
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "UefiShellDebug1CommandsLib.h"
17
18 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
19 {L"-n", TypeValue},
20 {L"-s", TypeValue},
21 {NULL, TypeMax}
22 };
23
24 typedef enum {
25 OutOfDiffPoint,
26 InDiffPoint,
27 InPrevDiffPoint
28 } READ_STATUS;
29
30 /**
31 Function to print differnt point data.
32
33 @param[in] FileName File name.
34 @param[in] FileTag File tag name.
35 @param[in] Buffer Data buffer to be printed.
36 @param[in] BufferSize Size of the data to be printed.
37 @param[in] Address Address of the differnt point.
38 @param[in] DifferentBytes Total size of the buffer.
39
40 **/
41 VOID
42 PrintDifferentPoint(
43 CONST CHAR16 *FileName,
44 CHAR16 *FileTag,
45 UINT8 *Buffer,
46 UINT64 BufferSize,
47 UINTN Address,
48 UINT64 DifferentBytes
49 )
50 {
51 UINTN Index;
52
53 ShellPrintEx (-1, -1, L"%s: %s\r\n %08x:", FileTag, FileName, Address);
54
55 //
56 // Print data in hex-format.
57 //
58 for (Index = 0; Index < BufferSize; Index++) {
59 ShellPrintEx (-1, -1, L" %02x", Buffer[Index]);
60 }
61
62 if (BufferSize < DifferentBytes) {
63 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_END_OF_FILE), gShellDebug1HiiHandle);
64 }
65
66 ShellPrintEx (-1, -1, L" *");
67
68 //
69 // Print data in char-format.
70 //
71 for (Index = 0; Index < BufferSize; Index++) {
72 if (Buffer[Index] >= 0x20 && Buffer[Index] <= 0x7E) {
73 ShellPrintEx (-1, -1, L"%c", Buffer[Index]);
74 } else {
75 //
76 // Print dots for control characters
77 //
78 ShellPrintEx (-1, -1, L".");
79 }
80 }
81
82 ShellPrintEx (-1, -1, L"*\r\n");
83 }
84
85 /**
86 Function for 'comp' command.
87
88 @param[in] ImageHandle Handle to the Image (NULL if Internal).
89 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
90 **/
91 SHELL_STATUS
92 EFIAPI
93 ShellCommandRunComp (
94 IN EFI_HANDLE ImageHandle,
95 IN EFI_SYSTEM_TABLE *SystemTable
96 )
97 {
98 EFI_STATUS Status;
99 LIST_ENTRY *Package;
100 CHAR16 *ProblemParam;
101 CHAR16 *FileName1;
102 CHAR16 *FileName2;
103 CONST CHAR16 *TempParam;
104 SHELL_STATUS ShellStatus;
105 SHELL_FILE_HANDLE FileHandle1;
106 SHELL_FILE_HANDLE FileHandle2;
107 UINT64 Size1;
108 UINT64 Size2;
109 UINT64 DifferentBytes;
110 UINT64 DifferentCount;
111 UINT8 DiffPointNumber;
112 UINT8 OneByteFromFile1;
113 UINT8 OneByteFromFile2;
114 UINT8 *DataFromFile1;
115 UINT8 *DataFromFile2;
116 UINTN InsertPosition1;
117 UINTN InsertPosition2;
118 UINTN DataSizeFromFile1;
119 UINTN DataSizeFromFile2;
120 UINTN TempAddress;
121 UINTN Index;
122 UINTN DiffPointAddress;
123 READ_STATUS ReadStatus;
124
125 ShellStatus = SHELL_SUCCESS;
126 Status = EFI_SUCCESS;
127 FileName1 = NULL;
128 FileName2 = NULL;
129 FileHandle1 = NULL;
130 FileHandle2 = NULL;
131 DataFromFile1 = NULL;
132 DataFromFile2 = NULL;
133 ReadStatus = OutOfDiffPoint;
134 DifferentCount = 10;
135 DifferentBytes = 4;
136 DiffPointNumber = 0;
137 InsertPosition1 = 0;
138 InsertPosition2 = 0;
139 TempAddress = 0;
140 DiffPointAddress = 0;
141
142 //
143 // initialize the shell lib (we must be in non-auto-init...)
144 //
145 Status = ShellInitialize();
146 ASSERT_EFI_ERROR(Status);
147
148 Status = CommandInit();
149 ASSERT_EFI_ERROR(Status);
150
151 //
152 // parse the command line
153 //
154 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
155 if (EFI_ERROR(Status)) {
156 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
157 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"comp", ProblemParam);
158 FreePool(ProblemParam);
159 ShellStatus = SHELL_INVALID_PARAMETER;
160 } else {
161 ASSERT(FALSE);
162 }
163 } else {
164 if (ShellCommandLineGetCount(Package) > 3) {
165 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"comp");
166 ShellStatus = SHELL_INVALID_PARAMETER;
167 } else if (ShellCommandLineGetCount(Package) < 3) {
168 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"comp");
169 ShellStatus = SHELL_INVALID_PARAMETER;
170 } else {
171 TempParam = ShellCommandLineGetRawValue(Package, 1);
172 ASSERT(TempParam != NULL);
173 FileName1 = ShellFindFilePath(TempParam);
174 if (FileName1 == NULL) {
175 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
176 ShellStatus = SHELL_NOT_FOUND;
177 } else {
178 Status = ShellOpenFileByName(FileName1, &FileHandle1, EFI_FILE_MODE_READ, 0);
179 if (EFI_ERROR(Status)) {
180 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
181 ShellStatus = SHELL_NOT_FOUND;
182 }
183 }
184 TempParam = ShellCommandLineGetRawValue(Package, 2);
185 ASSERT(TempParam != NULL);
186 FileName2 = ShellFindFilePath(TempParam);
187 if (FileName2 == NULL) {
188 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
189 ShellStatus = SHELL_NOT_FOUND;
190 } else {
191 Status = ShellOpenFileByName(FileName2, &FileHandle2, EFI_FILE_MODE_READ, 0);
192 if (EFI_ERROR(Status)) {
193 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
194 ShellStatus = SHELL_NOT_FOUND;
195 }
196 }
197 if (ShellStatus == SHELL_SUCCESS) {
198 Status = gEfiShellProtocol->GetFileSize(FileHandle1, &Size1);
199 ASSERT_EFI_ERROR(Status);
200 Status = gEfiShellProtocol->GetFileSize(FileHandle2, &Size2);
201 ASSERT_EFI_ERROR(Status);
202
203 if (ShellCommandLineGetFlag (Package, L"-n")) {
204 TempParam = ShellCommandLineGetValue (Package, L"-n");
205 if (TempParam == NULL) {
206 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"comp", L"-n");
207 ShellStatus = SHELL_INVALID_PARAMETER;
208 } else {
209 if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)TempParam, L"all") == 0) {
210 DifferentCount = MAX_UINTN;
211 } else {
212 Status = ShellConvertStringToUint64 (TempParam, &DifferentCount, FALSE, TRUE);
213 if (EFI_ERROR(Status) || DifferentCount == 0) {
214 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"comp", TempParam, L"-n");
215 ShellStatus = SHELL_INVALID_PARAMETER;
216 }
217 }
218 }
219 }
220
221 if (ShellCommandLineGetFlag (Package, L"-s")) {
222 TempParam = ShellCommandLineGetValue (Package, L"-s");
223 if (TempParam == NULL) {
224 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"comp", L"-s");
225 ShellStatus = SHELL_INVALID_PARAMETER;
226 } else {
227 Status = ShellConvertStringToUint64 (TempParam, &DifferentBytes, FALSE, TRUE);
228 if (EFI_ERROR(Status) || DifferentBytes == 0) {
229 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"comp", TempParam, L"-s");
230 ShellStatus = SHELL_INVALID_PARAMETER;
231 } else {
232 if (DifferentBytes > MAX (Size1, Size2)) {
233 DifferentBytes = MAX (Size1, Size2);
234 }
235 }
236 }
237 }
238 }
239
240 if (ShellStatus == SHELL_SUCCESS) {
241 DataFromFile1 = AllocateZeroPool ((UINTN)DifferentBytes);
242 DataFromFile2 = AllocateZeroPool ((UINTN)DifferentBytes);
243 if (DataFromFile1 == NULL || DataFromFile2 == NULL) {
244 ShellStatus = SHELL_OUT_OF_RESOURCES;
245 SHELL_FREE_NON_NULL (DataFromFile1);
246 SHELL_FREE_NON_NULL (DataFromFile2);
247 }
248 }
249
250 if (ShellStatus == SHELL_SUCCESS) {
251 while (DiffPointNumber < DifferentCount) {
252 DataSizeFromFile1 = 1;
253 DataSizeFromFile2 = 1;
254 OneByteFromFile1 = 0;
255 OneByteFromFile2 = 0;
256 Status = gEfiShellProtocol->ReadFile (FileHandle1, &DataSizeFromFile1, &OneByteFromFile1);
257 ASSERT_EFI_ERROR (Status);
258 Status = gEfiShellProtocol->ReadFile (FileHandle2, &DataSizeFromFile2, &OneByteFromFile2);
259 ASSERT_EFI_ERROR (Status);
260
261 TempAddress++;
262
263 //
264 // 1.When end of file and no chars in DataFromFile buffer, then break while.
265 // 2.If no more char in File1 or File2, The ReadStatus is InPrevDiffPoint forever.
266 // So the previous different point is the last one, then break the while block.
267 //
268 if ( (DataSizeFromFile1 == 0 && InsertPosition1 == 0 && DataSizeFromFile2 == 0 && InsertPosition2 == 0) ||
269 (ReadStatus == InPrevDiffPoint && (DataSizeFromFile1 == 0 || DataSizeFromFile2 == 0))
270 ) {
271 break;
272 }
273
274 if (ReadStatus == OutOfDiffPoint) {
275 if (OneByteFromFile1 != OneByteFromFile2) {
276 ReadStatus = InDiffPoint;
277 DiffPointAddress = TempAddress;
278 if (DataSizeFromFile1 == 1) {
279 DataFromFile1[InsertPosition1++] = OneByteFromFile1;
280 }
281 if (DataSizeFromFile2 == 1) {
282 DataFromFile2[InsertPosition2++] = OneByteFromFile2;
283 }
284 }
285 } else if (ReadStatus == InDiffPoint) {
286 if (DataSizeFromFile1 == 1) {
287 DataFromFile1[InsertPosition1++] = OneByteFromFile1;
288 }
289 if (DataSizeFromFile2 == 1) {
290 DataFromFile2[InsertPosition2++] = OneByteFromFile2;
291 }
292 } else if (ReadStatus == InPrevDiffPoint) {
293 if (OneByteFromFile1 == OneByteFromFile2) {
294 ReadStatus = OutOfDiffPoint;
295 }
296 }
297
298 //
299 // ReadStatus should be always equal InDiffPoint.
300 //
301 if ( InsertPosition1 == DifferentBytes ||
302 InsertPosition2 == DifferentBytes ||
303 (DataSizeFromFile1 == 0 && DataSizeFromFile2 == 0)
304 ) {
305
306 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_DIFFERENCE_POINT), gShellDebug1HiiHandle, ++DiffPointNumber);
307 PrintDifferentPoint (FileName1, L"File1", DataFromFile1, InsertPosition1, DiffPointAddress, DifferentBytes);
308 PrintDifferentPoint (FileName2, L"File2", DataFromFile2, InsertPosition2, DiffPointAddress, DifferentBytes);
309
310 //
311 // One of two buffuers is empty, it means this is the last different point.
312 //
313 if (InsertPosition1 == 0 || InsertPosition2 == 0) {
314 break;
315 }
316
317 for (Index = 1; Index < InsertPosition1 && Index < InsertPosition2; Index++) {
318 if (DataFromFile1[Index] == DataFromFile2[Index]) {
319 ReadStatus = OutOfDiffPoint;
320 break;
321 }
322 }
323
324 if (ReadStatus == OutOfDiffPoint) {
325 //
326 // Try to find a new different point in the rest of DataFromFile.
327 //
328 for (; Index < MAX (InsertPosition1,InsertPosition2); Index++) {
329 if (DataFromFile1[Index] != DataFromFile2[Index]) {
330 ReadStatus = InDiffPoint;
331 DiffPointAddress += Index;
332 break;
333 }
334 }
335 } else {
336 //
337 // Doesn't find a new different point, still in the same different point.
338 //
339 ReadStatus = InPrevDiffPoint;
340 }
341
342 CopyMem (DataFromFile1, DataFromFile1 + Index, InsertPosition1 - Index);
343 CopyMem (DataFromFile2, DataFromFile2 + Index, InsertPosition2 - Index);
344
345 SetMem (DataFromFile1 + InsertPosition1 - Index, (UINTN)DifferentBytes - InsertPosition1 + Index, 0);
346 SetMem (DataFromFile2 + InsertPosition2 - Index, (UINTN)DifferentBytes - InsertPosition2 + Index, 0);
347
348 InsertPosition1 -= Index;
349 InsertPosition2 -= Index;
350 }
351 }
352
353 SHELL_FREE_NON_NULL (DataFromFile1);
354 SHELL_FREE_NON_NULL (DataFromFile2);
355
356 if (DiffPointNumber == 0) {
357 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_PASS), gShellDebug1HiiHandle);
358 } else {
359 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_FAIL), gShellDebug1HiiHandle);
360 }
361 }
362 }
363
364 ShellCommandLineFreeVarList (Package);
365 }
366 SHELL_FREE_NON_NULL(FileName1);
367 SHELL_FREE_NON_NULL(FileName2);
368
369 if (FileHandle1 != NULL) {
370 gEfiShellProtocol->CloseFile(FileHandle1);
371 }
372 if (FileHandle2 != NULL) {
373 gEfiShellProtocol->CloseFile(FileHandle2);
374 }
375
376 return (ShellStatus);
377 }