[PATCH] D66886: [yaml2obj][obj2yaml] - Use a single "Other" field instead of "Other", "Visibility" and "StOther".

George Rimar via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 29 06:02:38 PDT 2019


grimar added inline comments.


================
Comment at: lib/ObjectYAML/ELFYAML.cpp:850
+      uint8_t FlagValue = P.second;
+      if ((*Original & FlagValue) != FlagValue)
+        continue;
----------------
jhenderson wrote:
> I'm a bit confused with seeing an Optional being passed in without any check to see if it is None... but I see that was the case before.
Yes. This constructor is only used by `MappingNormalization` for outputing, i.e. for obj2yaml.
So we always have a value here. I wasn't sure if it worth to add a comment or not, since it is by design of `MappingNormalization` class.
I added an assert with a comment.


================
Comment at: lib/ObjectYAML/ELFYAML.cpp:857
+    if (*Original != 0) {
+      UnknownFlagsHolder = std::to_string(*Original);
+      Ret.push_back(UnknownFlagsHolder);
----------------
MaskRay wrote:
> jhenderson wrote:
> > llvm::to_string I think is preferred.
> `to_string` returns an allocated string => `Other`'s type can't be Optional<std::vector<StringRef>>
> 
> See below.
> llvm::to_string I think is preferred.

I can't use it because it wants me to include the 'ScopedPrinter.h'. I do not think it worth doing for a single place?

> to_string returns an allocated string => Other's type can't be Optional<std::vector<StringRef>>

That is why I had to use `UnknownFlagsHolder`, it holds the string allocated until 'NormalizedOther' is destroyed.




================
Comment at: lib/ObjectYAML/ELFYAML.cpp:877-880
+    llvm::WithColor::error()
+        << "an unknown value is used for symbol's 'Other' field: " << Name
+        << ".\n";
+    exit(1);
----------------
MaskRay wrote:
> jhenderson wrote:
> > Do other yaml2obj/obj2yaml error messages end with a full stop?
> > 
> > Also, this error reporting method here makes me uncomfortable, since we're in the middle of a library. Is there any sensible way to propagate the error back up the stack?
> In ELFYAML.h
> 
> ```
>   template <>
>   struct MappingTraits<ELFYAML::Symbol> {
>   ...
> +   std::string Err;
> ```
> 
> In ELFYAML.cpp,
> 
> ```
>   StringRef MappingTraits<ELFYAML::Symbol>::validate(IO &IO,
>                                                    ELFYAML::Symbol &Symbol) {
> +  if (!Err.empty())
> +    return Err;
> ...
>   }
> 
> -   NormalizedOther(IO &IO, Optional<uint8_t> Original) : YamlIO(IO) {
> +  NormalizedOther(IO &IO, ELFYAML::Symbol &Sym) : YamlIO(IO) {
> 
> -  MappingNormalization<NormalizedOther, Optional<uint8_t>> Keys(IO, Symbol.Other);
> +  MappingNormalization<NormalizedOther, ELFYAML::Symbol> Keys(IO, Symbol);
> ```
> 
> I haven't verified if this approach works, if it does, the error can be propagated back via `validate()`.
> Do other yaml2obj/obj2yaml error messages end with a full stop?

Yes.

> Also, this error reporting method here makes me uncomfortable, since we're in the middle of a library. Is there any sensible way to propagate the error back up the stack?

This is a common problem, `exit(1)` is already used in a 3 more places in lib\ObjectYAML. Having that, what about if I suggest a follow-up refactoring(s) for all those places and this one?


================
Comment at: lib/ObjectYAML/ELFYAML.cpp:897-899
+    // STV_* values are just enumeration values. We add them in a reversed order
+    // because when we converting the st_other to named constants we want to use
+    // a maximum number of bits on each step.
----------------
jhenderson wrote:
> converting -> convert
> 
> I'm not sure what's "reversed" about the order, or what the bits have to do with anything?
`STV_*`s have the following values:

```
STV_DEFAULT = 0,  // Visibility is specified by binding type
STV_INTERNAL = 1, // Defined by processor supplements
STV_HIDDEN = 2,   // Not visible to other components
STV_PROTECTED = 3 // Visible in other components but not preemptable
```

If we have, for example `st_other` == 3. We want to dump it as `STV_PROTECTED` and not as `STV_INTERNAL` + `STV_HIDDEN`.
So we need to handle the `STV_PROTECTED` first and because of that I had to list them as `3, 2, 1`, i.e. in inversed order.

I updated the comment.


================
Comment at: lib/ObjectYAML/ELFYAML.cpp:910-911
+    // MIPS is not consistent. All of the STO_MIPS_* values are bit flags,
+    // except STO_MIPS_MIPS16 which overlaps them. It should be checked first,
+    // so we add it first.
+    if (EMachine == ELF::EM_MIPS) {
----------------
jhenderson wrote:
> Why does MIPS16 need checking first? This comment should explain this point.
I updated the comment.


================
Comment at: lib/ObjectYAML/ELFYAML.cpp:939-943
   // Symbol's Other field is a bit special. It is a bit field that represents
-  // st_other and usually holds symbol visibility. When we write a YAML document
-  // we split it into two fields named "Visibility" and "Other". The latter one
-  // usually holds no value, and so is almost never printed, although some
-  // targets (e.g. MIPS) may use it to specify the named bits to set (e.g.
-  // STO_MIPS_OPTIONAL). For producing broken objects we want to allow writing
-  // any value to st_other. To do this we allow one more field called "StOther".
-  // If it is present in a YAML document, we set st_other to its integer value
-  // whatever it is.
-  // obj2yaml should not print 'StOther', it should print 'Visibility' and
-  // 'Other' fields instead.
-  assert(!IO.outputting() || !Symbol.StOther.hasValue());
-  IO.mapOptional("StOther", Symbol.StOther);
+  // st_other and usually holds symbol visibility. But also depending on a
+  // platform it can contain bitfields and regular values, or even sometimes a
+  // crazy mix of them (see comments for NormalizedOther). Because of that we
+  // need a special handling.
----------------
jhenderson wrote:
> Calling st_other/Other a bit field is incorrect, even for regular ELFs, since symbol visibility isn't a bit field (STV_PROTECTED is 0x3 for example).
> 
> I'd change the first sentence to say "It is usually a field that represents st_other and holds the symbol visibility."
> 
> Then I'd make the next sentence say "However, on some platforms, it can contain bit field and regular values, or even ..."
> 
> And the last sentence "Because of this, we need special handling."
Thanks!


================
Comment at: test/tools/obj2yaml/elf-symbol-visibility.yaml:14
+# CHECK-NEXT:   - Name: internal
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:      - STV_INTERNAL
----------------
MaskRay wrote:
> jhenderson wrote:
> > grimar wrote:
> > > MaskRay wrote:
> > > > MaskRay wrote:
> > > > > jhenderson wrote:
> > > > > > Is there any way straightforward way of forcing obj2yaml to produce output in the form `Other: [ STV_HIDDEN ]` etc?
> > > > > Not straightforward but I managed to find an approach..
> > > > > 
> > > > > ```
> > > > >  struct NormalizedOther {
> > > > > +  struct Piece {
> > > > > +    std::string Str;
> > > > > +  };
> > > > >  ...
> > > > > -  Optional<std::vector<StringRef>> Other;
> > > > > +  Optional<std::vector<Piece>> Other;
> > > > >    std::string UnknownFlagsHolder;
> > > > >  };
> > > > >  } // namespace
> > > > >  
> > > > > +template<>
> > > > > +struct ScalarTraits<NormalizedOther::Piece> {
> > > > > +  static void output(const NormalizedOther::Piece &Val, void *, raw_ostream &Out) {
> > > > > +    Out << Val.Str;
> > > > > +  }
> > > > > +  static StringRef input(StringRef Scalar, void *, NormalizedOther::Piece &Val) {
> > > > > +    Val.Str = Scalar.str();
> > > > > +    return {};
> > > > > +  }
> > > > > +  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
> > > > > +};
> > > > > +template<> struct SequenceElementTraits<NormalizedOther::Piece> {
> > > > > +  static const bool flow = true;
> > > > > +};
> > > > > ```
> > > > > 
> > > > > This way obj2yaml will dump: `Other: [ STV_HIDDEN ]`
> > > > Oh, I think StringRef should be fine.
> > > > 
> > > > ```
> > > > +  struct Piece {
> > > > +    StringRef Str;
> > > > +  };
> > > > ```
> > > Thanks a lot for this! I was wondering yesterday how to achieve it, but did not have chance to experiment with it.
> > > 
> > > My question is: do we want it? I.e it adds a bit of complexity to the code, but makes the output better.
> > > I really like it the `Other: [ STV_HIDDEN ]` output style more, just want to check this point before addressing.
> > > 
> > > (I'll try to address this and all other comments today.)
> > I'm happy either way. I think it's a little confusing that obj2yaml might produce different output to what looks good and would be written in all the tests, so I think the extra complexity is probably worth it. It's not too bad, I think?
> I also think the extra complexity is worth it.
I was able to get rid of using `struct` (used `LLVM_YAML_STRONG_TYPEDEF(StringRef, StOtherPiece)` declaration instead).
Seems it is a little bit simpler.


================
Comment at: test/tools/yaml2obj/elf-symbol-stother.yaml:72
 
-# ERR2: error: StOther cannot be specified for Symbol with either Visibility or Other
+## The same, but the different syntax is used to describe "Other".
 
----------------
jhenderson wrote:
> but the -> but a
> 
> Does this alternative syntax just come out automatically? Otherwise, I don't think we need to support both forms.
Yes it is supported automatically. I added it to show we can use the syntax produced by obj2yaml, which was different before this diff.
Since now they have a similar syntax, I removed this test case completely.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66886/new/

https://reviews.llvm.org/D66886





More information about the llvm-commits mailing list