[PATCH v5 1/2] covoar: Fix NOP execution marking

Alex White alex.white at oarcorp.com
Thu Mar 25 20:42:08 UTC 2021


On Thu, Mar 25, 2021 at 2:38 PM Gedare Bloom <gedare at rtems.org> wrote:
>
> On Thu, Mar 25, 2021 at 10:05 AM Joel Sherrill <joel at rtems.org> wrote:
> >
> >
> >
> > On Thu, Mar 25, 2021 at 10:42 AM Gedare Bloom <gedare at rtems.org> wrote:
> >>
> >> On Thu, Mar 18, 2021 at 12:05 PM Alex White <alex.white at oarcorp.com> wrote:
> >> > -    // Mark the start of each instruction in the coverage map.
> >> > -    for (auto& instruction : instructions) {
> >> > -      coverageMap.setIsStartOfInstruction( instruction.address );
> >> > -    }
> >> > +      // Find the address of the first instruction.
> >> > +      for (auto& line : instructions) {
> >> > +        if (!line.isInstruction) {
> >> > +          continue;
> >> > +        }
> >> > +
> >> > +        firstInstructionAddress = line.address;
> >> > +        break;
> >> > +      }
> >> This is a poorly written loop. Anytime you use continue/break to
> >> control the loop iteration, something is going awry. You can write
> >> this code equivalently without any continue or break.
> >
> >
> > This loop is very deliberately constructed not to be a for loop because
> > you need the ability to break at different points to debug issues. Alex
> > and I spent hours in this loop debugging which I think would have
> > been more difficult to debug if all the conditions were in a for loop.
> > This loop was written to explicitly have breakpoints for various
> > conditions.
> >
> > There have been multiple issues with the information reported with
> > size/length being at the top of that list. Before Alex found the source
> > of that (not covoar), it resulted in an infinite loop.
> >
> > I suppose it can be changed to a for loop as purer academically but
> > it loses significantly on ability to set breakpoints and debug if there
> > ever is an issue again.
> >
> > Are you willing to make that trade?
> >
>
> You know that what we debug is often much uglier than what we publish.
> At least, simplify the logic to let the loop work for you.
>
> for (auto& line : instructions) {
>   if ( line.isInstruction ) {
>     firstInstructionAddress = line.address;
>     break;
>   }
> }

I will make this change.

>
> Using continue/break to control loops is antithetical to using loops,
> and probably doesn't do the compiler any good.
>
> >> > +        if (!line.isInstruction) {
> >> > +          continue;
> >> > +        }
> >> > +
> >> > +
> >> > +        break;
> >> > +      }
> >>
> >> > +
> >> > +      if (firstInstructionAddress == UINT32_MAX) {
> >> > +        std::ostringstream what;
> >> > +        what << "Could not find first instruction address for symbol "
> >> > +          << symbolName << " in " << executableInfo->getFileName();
> >> > +        throw rld::error( what, "Coverage::finalizeSymbol" );
> >> > +      }
> >> > +
> >> > +      int rangeIndex;
> >> > +      uint32_t lowAddress = UINT32_MAX;
> >> > +      for (rangeIndex = 0; ; rangeIndex++) {
> >> > +        lowAddress = coverageMap.getLowAddressOfRange(rangeIndex);
> >> > +
> >> > +        if (firstInstructionAddress == lowAddress) {
> >> > +          break;
> >> ditto... if you're goin to break the loop on this condition, why not
> >> use this in your for loop?
> >> for (rangeIndex = 0; firstInstructionAddress != lowAddress ; rangeIndex++) {

I will make this change, too.

> >>
> >> > +        }
> >> > +      }
> >> >
> >> > -    // Create a unified coverage map for the symbol.
> >> > -    SymbolsToAnalyze->createCoverageMap(
> >> > -      executableInfo->getFileName().c_str(), symbolName, size
> >> > -    );
> >> > +      uint32_t sizeWithoutNops = coverageMap.getSizeOfRange(rangeIndex);
> >> > +      uint32_t size = sizeWithoutNops;
> >> > +      uint32_t highAddress = lowAddress + size - 1;
> >> > +      uint32_t computedHighAddress = highAddress;
> >> > +
> >> > +      // Find the high address as reported by the address of the last NOP
> >> > +      // instruction. This ensures that NOPs get marked as executed later.
> >> > +      for (auto instruction = instructions.rbegin();
> >> > +          instruction != instructions.rend();
> >> > +          instruction++) {
> >> > +        if (instruction->isInstruction) {
> >> > +          if (instruction->isNop) {
> >> > +            computedHighAddress = instruction->address + instruction->nopSize;
> >> > +          }
> >> > +          break;
> >> Here too.

I'm not sure I see a more clear way to write this loop while
eliminating the `break` statement.

Do you have a suggestion?

> >>
> >> > +        }
> >> > +      }
> >> > +
> >> > +      if (highAddress != computedHighAddress) {
> >> > +        std::cerr << "Function's high address differs between DWARF and objdump: "
> >> > +          << symbolName << " (0x" << std::hex << highAddress << " and 0x"
> >> > +          << computedHighAddress - 1 << ")" << std::dec << std::endl;
> >> > +        size = computedHighAddress - lowAddress;
> >> > +      }
> >> > +
> >> > +      // If there are NOT already saved instructions, save them.
> >> > +      SymbolInformation* symbolInfo = SymbolsToAnalyze->find( symbolName );
> >> > +      if (symbolInfo->instructions.empty()) {
> >> > +        symbolInfo->sourceFile = executableInfo;
> >> > +        symbolInfo->baseAddress = lowAddress;
> >> > +        symbolInfo->instructions = instructions;
> >> > +      }
> >> > +
> >> > +      // Add the symbol to this executable's symbol table.
> >> > +      SymbolTable* theSymbolTable = executableInfo->getSymbolTable();
> >> > +      theSymbolTable->addSymbol(
> >> > +        symbolName, lowAddress, highAddress - lowAddress + 1
> >> > +      );
> >> > +
> >> > +      // Mark the start of each instruction in the coverage map.
> >> > +      for (auto& instruction : instructions) {
> >> > +        coverageMap.setIsStartOfInstruction( instruction.address );
> >> > +      }
> >> > +
> >> > +      // Create a unified coverage map for the symbol.
> >> > +      SymbolsToAnalyze->createCoverageMap(
> >> > +        executableInfo->getFileName().c_str(), symbolName, size, sizeWithoutNops
> >> > +      );
> >> > +    } catch (const ExecutableInfo::CoverageMapNotFoundError& e) {
> >> > +      // Allow execution to continue even if a coverage map could not be
> >> > +      // found.
> >> > +      std::cerr << "Coverage map not found for symbol " << e.what()
> >> > +        << std::endl;
> >> > +    }
> >> >    }
> >> >
> >> >    ObjdumpProcessor::ObjdumpProcessor()
> >> > --
> >> > 2.27.0
> >> >
> >> > _______________________________________________
> >> > devel mailing list
> >> > devel at rtems.org
> >> > http://lists.rtems.org/mailman/listinfo/devel
> >> _______________________________________________
> >> devel mailing list
> >> devel at rtems.org
> >> http://lists.rtems.org/mailman/listinfo/devel
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel


More information about the devel mailing list