This is an archive of the discontinued LLVM Phabricator instance.

Add functionality to cvtres to parse all entries in res file.
ClosedPublic

Authored by ecbeckmann on May 14 2017, 10:34 PM.

Diff Detail

Repository
rL LLVM

Event Timeline

ecbeckmann created this revision.May 14 2017, 10:34 PM
ecbeckmann updated this revision to Diff 98957.May 15 2017, 1:42 AM

Use binary stream.

ecbeckmann updated this revision to Diff 98960.May 15 2017, 1:54 AM

Made it look nicer.

ecbeckmann edited the summary of this revision. (Show Details)May 15 2017, 1:55 AM
ecbeckmann added reviewers: zturner, ruiu, thakis.
ruiu edited edge metadata.May 15 2017, 4:47 PM

I'd recommend renaming ResFile WindowsRes or WindowsResource everywhere, as I don't think Res or ResFile sound very familiar even for those who have an experience of Windows development, and for those who don't know about it, Res has no evidence about what that is.

llvm/include/llvm/Object/Binary.h
60 ↗(On Diff #98960)

You want to add comment that this is Windows Resource, just like above enums.

Maybe ID_WINDOWS_RESOURCE is better? ID_RES seems too short.

llvm/include/llvm/Object/ResFile.h
10 ↗(On Diff #98960)

the Windows .res, as Unix developers usually don't know what .res is.

25 ↗(On Diff #98960)

nit: remove

28–30 ↗(On Diff #98960)

You are using this macro only three times in this file, so it is better not to use it. In general you want to avoid using C macros, particularly in header files as it could conflict with .cpp files using the same identifier (unless you #undef the macro at end of the header.)

51 ↗(On Diff #98960)

remove

ruiu added inline comments.May 15 2017, 4:47 PM
llvm/include/llvm/Object/ResFile.h
45 ↗(On Diff #98960)

I believe we should use llvm::Error instead of std::error_code for new code.

56 ↗(On Diff #98960)

Looks like you want to allow users instantiate this class only with createResFile(). If so, it's better to make the constructor private.

59 ↗(On Diff #98960)

Functions should start with a verb. Maybe getHeadEntry?

61 ↗(On Diff #98960)

v -> V

83–84 ↗(On Diff #98960)

We have alignTo function to do this.

87 ↗(On Diff #98960)

Please fix format.

llvm/lib/Object/ResFile.cpp
38 ↗(On Diff #98960)

Format.

llvm/tools/llvm-cvtres/llvm-cvtres.cpp
79–81 ↗(On Diff #98960)

It's more natural to do if (EC) reportError(...).

zturner added inline comments.May 15 2017, 5:03 PM
llvm/include/llvm/Object/Binary.h
60 ↗(On Diff #98960)

Maybe ID_WinRes, // Windows resource data

llvm/include/llvm/Object/ResFile.h
10 ↗(On Diff #98960)

Also maybe a brief sentence about what a .res file is.

28–30 ↗(On Diff #98960)

Alternatively, move the macro to a cpp file (see below for related comment), or move the macro to the same place where errorToErrorCode is defined, so other people can make use of it and we don't have to copy the code around anymore.

32–34 ↗(On Diff #98960)

This can probably go to the cpp file if you de-inline the functions below.

36 ↗(On Diff #98960)

Same.

68 ↗(On Diff #98960)

I think you should store the BinaryByteStream here in this class, not in the Ref class. This makes a lot of things much easier. See below for an example.

75 ↗(On Diff #98960)

None of these seem like good candidates for inline functions. As an aside, if we did want to inline them, the best thing to do is declare them in the body of the class, not after you have finished definiing the class. In any case, can you move these to a cpp file?

82–87 ↗(On Diff #98960)

Ideally we'd like to get rid of as much math as possible. BinaryStreamWriter has a function called padToAlign that does exactly this. Perhaps you could add alignTo(unsigned N) to `BinaryStreamReader which simply skips the appropriate number of bytes.

llvm/lib/Object/ResFile.cpp
29–32 ↗(On Diff #98960)

Since this code is already part of the ResFile class, I don't know if passing the Error as an output parameter is necessary. Just move the constructor logic to this function, and make the constructor (declared private), take final values that require no processing.

37–38 ↗(On Diff #98960)

If the BBS is in the ResFile instead of the ResFileRef, and the ResFileRef instead stores a BinaryStreamRef, you can just write:

return ResEntryRef(BBS.slice(LeadingSize, BBS.size()-LeadingSize));

zturner added inline comments.May 15 2017, 5:06 PM
llvm/lib/Object/ResFile.cpp
37–38 ↗(On Diff #98960)

Alternatively, return ResEntryRef(BBS.drop_front(LeadingSize).drop_back(LeadingSize));

zturner added inline comments.May 17 2017, 2:05 PM
llvm/include/llvm/Object/ResFile.h
68 ↗(On Diff #98960)

I made some improvements to the BinaryStreamClass recently, it should simplify some of this.

82–87 ↗(On Diff #98960)

BinaryStreamReader now has a method called padToAlignment. The entire rest of this function can just be replaced with:

RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t));
End = (Reader.bytesRemaining() == 0);
llvm/lib/Object/ResFile.cpp
37–38 ↗(On Diff #98960)

My bad, I misunderstood this code the first time. It's just return ResEntryRef(BBS.drop_front(LeadingSize));

ecbeckmann updated this revision to Diff 99379.May 17 2017, 5:54 PM
ecbeckmann marked 19 inline comments as done.

Updated error output to be more informative, also made more clear naming scheme, removed inlines, and made use of helper functions.

majnemer added inline comments.
llvm/lib/Support/BinaryStreamReader.cpp
14 ↗(On Diff #99379)

Why is this needed?

llvm/tools/llvm-cvtres/llvm-cvtres.cpp
125–132 ↗(On Diff #99379)

StringSwitch

ecbeckmann added inline comments.May 17 2017, 6:07 PM
llvm/include/llvm/Object/ResFile.h
28–30 ↗(On Diff #98960)

Moved to the cpp file. I'm not sure if we want to put into Error.h because there are some variations in the codebase between returning errors and error codes.

llvm/lib/Object/ResFile.cpp
37–38 ↗(On Diff #98960)

I opted to just have ResourceEntryRef take a BinaryStreamRef instead of an ArrayRef.

llvm/tools/llvm-cvtres/llvm-cvtres.cpp
79–81 ↗(On Diff #98960)

true....but llvm style guide prefers early return

ecbeckmann updated this revision to Diff 99382.May 17 2017, 6:20 PM
ecbeckmann marked an inline comment as done.

Removed unnecessary includes, added StringSwitch.

llvm/lib/Support/BinaryStreamReader.cpp
14 ↗(On Diff #99379)

woops! Forgot to remove that.

ecbeckmann updated this revision to Diff 99383.May 17 2017, 6:35 PM

Fixed some things my clang-format changed.

Reverted some things my clang-format touched for some reason.

zturner added inline comments.May 19 2017, 11:23 AM
llvm/include/llvm/Object/WindowsResource.h
1–2 ↗(On Diff #99383)

Can you fix this so that it's exactly 80 characters so it doesn't wrap?

llvm/lib/Object/WindowsResource.cpp
33–36 ↗(On Diff #99383)

BBS = BinaryByteStream(Data.getBuffer(), support::little).drop_front(LeadingSize);

47 ↗(On Diff #99383)

return llvm::make_unique<WindowsResource>(Source);

64–71 ↗(On Diff #99383)

Maybe I'm missing something, but I don't think any of these lines are needed? You're computing Offset here by adding together the sizes of the two fields you just wrote. Then subtracting the size of the two fields you just wrote, at which point Offset is going to be 0. So you're skipping zero bytes, then padding to 4 byte alignment, but since you just read 2 uint32s, it should already be 4 byte aligned.

I think you can just delete all of this?

llvm/tools/llvm-cvtres/ResCOFFWriter.h
1–18 ↗(On Diff #99383)

Do we need a header file just for this? Maybe just put it in llvm-cvtres.h?

llvm/tools/llvm-cvtres/llvm-cvtres.cpp
15 ↗(On Diff #99383)

Remove this include. In the future though, stadard includes go after llvm includes.

121 ↗(On Diff #99383)

Remove

122–126 ↗(On Diff #99383)

std::string MachineString = InputArgs.getLastArgValue(OPT_MACHINE).upper();

153 ↗(On Diff #99383)

const auto &File

174–183 ↗(On Diff #99383)

outs() << StringSwitch<machine>(Machine).(machine::ARM, "ARM")...

llvm/tools/llvm-cvtres/llvm-cvtres.h
15 ↗(On Diff #99383)

Can you put this in the same file as the other enum? That said, it looks like maybe it is only used from 1 file? In that case make it static inline in the file where you need it.

ruiu added inline comments.May 19 2017, 11:35 AM
llvm/include/llvm/Object/Binary.h
137 ↗(On Diff #99603)

isWinRes

llvm/include/llvm/Object/WindowsResource.h
1–2 ↗(On Diff #99603)

Format.

58 ↗(On Diff #99603)

Format?

59 ↗(On Diff #99603)

Do you need this?

llvm/lib/Object/WindowsResource.cpp
47–48 ↗(On Diff #99603)

return make_unique<WindowsResource>(Source)?

llvm/test/tools/llvm-cvtres/resource.test
5–6 ↗(On Diff #99603)

Since you have only one test, you can omit -check-prefix, and s/TEST_RES/CHECK/. ("CHECK" is the default name.)

llvm/tools/llvm-cvtres/llvm-cvtres.cpp
162 ↗(On Diff #99603)

You defined cvtres_error just for this line? If so, it seems too much to me. You could just do reportError("Unsupported machine architecture").

184 ↗(On Diff #99603)

If you add \n at end of all the above strings, you can remove this line. This is shorter and probably better

if (Machine == machine::ARM)
  outs() << "ARM\n";
else if (Machine == machine::X86")
  outs() << "X86\n";
else
 outs() << "X64"\n";
zturner added inline comments.May 19 2017, 11:39 AM
llvm/lib/Object/WindowsResource.cpp
64–71 ↗(On Diff #99383)

Ahh I think I follow now. But why are you just reading the data and header size, but not the *actual* data or headers?

ecbeckmann updated this revision to Diff 99621.May 19 2017, 1:42 PM
ecbeckmann marked 15 inline comments as done.

some minor fixes

ecbeckmann added inline comments.May 19 2017, 1:43 PM
llvm/lib/Object/WindowsResource.cpp
64–71 ↗(On Diff #99383)

This patch was just to add functionality for iterating through the entries without reading them just yet. It will be easy in future patches to add functions to ResourceEntryRef to return specific fields from each entry.

47–48 ↗(On Diff #99603)

Unfortunately, since we made the constructor private it cannot be accessed by make_unique

llvm/tools/llvm-cvtres/ResCOFFWriter.h
1–18 ↗(On Diff #99383)

When I eventually get to generating the COFF output file, that code will live in this file. This module is what needs to know what machine type it is generating for, so I thought I should place the enum here. But for now, I guess we can remove this file.

llvm/tools/llvm-cvtres/llvm-cvtres.cpp
174–183 ↗(On Diff #99383)

Unfortunately StringSwitch only goes from StringRef -> value, not the other way around. There's no constructor that takes a value parameter.

llvm/tools/llvm-cvtres/llvm-cvtres.h
15 ↗(On Diff #99383)

In future patches this function will surely be used in multiple files.

zturner added inline comments.May 19 2017, 2:03 PM
llvm/lib/Object/WindowsResource.cpp
33–36 ↗(On Diff #99621)

My motivation for suggesting the change was ultimately to kill the reinterpret_cast which we should avoid wherever possible. Can we try this?

BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize), support::little);
ruiu added inline comments.May 19 2017, 2:19 PM
llvm/include/llvm/Object/WindowsResource.h
61 ↗(On Diff #99621)

Remove inline as it is redundant. When you write a function definition inside class declaration, it is inline by default.

llvm/test/tools/llvm-cvtres/resource.test
5–6 ↗(On Diff #99621)

Now you can write this in a single line.

llvm/tools/llvm-cvtres/llvm-cvtres.cpp
72 ↗(On Diff #99621)

I think err is unbuffered, so you don't need flush().

81 ↗(On Diff #99621)

Can you run clang-format-diff? There are many formatting errors (in terms of the LLVM coding style) in this file.

llvm/tools/llvm-cvtres/llvm-cvtres.h
15 ↗(On Diff #99383)

Add this header in the future patch which needs this header. Adding a stub is usually fine, but this file seems too stub-y.

ecbeckmann updated this revision to Diff 99640.May 19 2017, 3:57 PM
ecbeckmann marked 5 inline comments as done.

Cleaned up some more.

ecbeckmann added inline comments.May 19 2017, 3:57 PM
llvm/tools/llvm-cvtres/llvm-cvtres.h
15 ↗(On Diff #99383)

The header file itself is has already been commited into LLVM...are you saying we should not put the declarations here yet?

zturner added inline comments.May 19 2017, 4:06 PM
llvm/lib/Object/WindowsResource.cpp
64–71 ↗(On Diff #99383)

I see. Can you then change to this?

BinaryStreamRef HeaderBytes;
BinaryStreamRef DataBytes;
RETURN_IF_ERROR(Reader.readStreamRef(HeaderBytes, HeaderSize));
RETURN_IF_ERROR(Reader.readStreamRef(DataBytes, DataSize));
RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t));

BTW, it seems strange to me that data size comes first and header size comes second. Are you sure the first two reads aren't reversed?

At least this way the logic is more clear and there's no math or manual jumping around which makes it hard to follow.

ecbeckmann updated this revision to Diff 99655.May 19 2017, 5:52 PM
ecbeckmann marked an inline comment as done.

Load header and data sections into stream readers.

ecbeckmann added inline comments.May 19 2017, 5:53 PM
llvm/lib/Object/WindowsResource.cpp
64–71 ↗(On Diff #99383)

Ah I see. In this case HeaderBytes and DataBytes should be made class variables as well.

I agree that it is a strange convention, and indeed the actual Microsoft documentation says that the order is Header Size followed by Data Size. However, this documentation is incorrect, and I've verified that the order is in fact Data Size > Header Size by examining several .res files in the hexcode editor.

zturner accepted this revision.May 19 2017, 5:58 PM

lgtm after reflowing the comment.

llvm/lib/Object/WindowsResource.cpp
83–88 ↗(On Diff #99655)

Can you move this comment up a line? It looks pretty bad like this.

This revision is now accepted and ready to land.May 19 2017, 5:58 PM
ecbeckmann updated this revision to Diff 99660.May 19 2017, 6:59 PM
ecbeckmann marked an inline comment as done.

Fixed formatting problems

llvm/include/llvm/Object/WindowsResource.h
59 ↗(On Diff #99603)

Yes because the destructor is declared virtual in the base class.

ecbeckmann updated this revision to Diff 99661.May 19 2017, 7:01 PM

One more formatting issue

This revision was automatically updated to reflect the committed changes.