<div dir="ltr">Michael,<div><br></div><div>This patch doesn't seem to compile with Clang on Linux.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jul 8, 2015 at 5:21 PM, Michael J. Spencer <span dir="ltr"><<a href="mailto:bigcheesegs@gmail.com" target="_blank">bigcheesegs@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: mspencer<br>
Date: Wed Jul 8 19:21:06 2015<br>
New Revision: 241765<br>
<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject-3Frev-3D241765-26view-3Drev&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=UtQxE0-VNFK75WWnQdSO4HpXT1LjCGDOo_9WnJrGFGw&s=1FBznK-Q1_Dsjl1Tbyli0BS3KpMlzW8XnIIMbqtdFvw&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=241765&view=rev</a><br>
Log:<br>
[Object][ELF] Support dumping hash-tables from files with no section table.<br>
<br>
Added:<br>
llvm/trunk/test/Object/Inputs/no-section-table.so<br>
llvm/trunk/test/Object/no-section-table.test<br>
Modified:<br>
llvm/trunk/include/llvm/Object/ELF.h<br>
llvm/trunk/include/llvm/Object/ELFTypes.h<br>
llvm/trunk/tools/llvm-readobj/ELFDumper.cpp<br>
llvm/trunk/tools/llvm-readobj/ObjDumper.h<br>
llvm/trunk/tools/llvm-readobj/StreamWriter.h<br>
llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/Object/ELF.h<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_include_llvm_Object_ELF.h-3Frev-3D241765-26r1-3D241764-26r2-3D241765-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=UtQxE0-VNFK75WWnQdSO4HpXT1LjCGDOo_9WnJrGFGw&s=KiGAoAr94U0SRGWNlnpW54oDPoq-wGim8Ubl4pqiWZQ&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/ELF.h?rev=241765&r1=241764&r2=241765&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Object/ELF.h (original)<br>
+++ llvm/trunk/include/llvm/Object/ELF.h Wed Jul 8 19:21:06 2015<br>
@@ -16,6 +16,7 @@<br>
<br>
#include "llvm/ADT/ArrayRef.h"<br>
#include "llvm/ADT/DenseMap.h"<br>
+#include "llvm/ADT/IntervalMap.h"<br>
#include "llvm/ADT/PointerIntPair.h"<br>
#include "llvm/ADT/SmallVector.h"<br>
#include "llvm/ADT/StringSwitch.h"<br>
@@ -139,6 +140,7 @@ public:<br>
typedef Elf_Verneed_Impl<ELFT> Elf_Verneed;<br>
typedef Elf_Vernaux_Impl<ELFT> Elf_Vernaux;<br>
typedef Elf_Versym_Impl<ELFT> Elf_Versym;<br>
+ typedef Elf_Hash<ELFT> Elf_Hash;<br>
typedef ELFEntityIterator<const Elf_Dyn> Elf_Dyn_Iter;<br>
typedef iterator_range<Elf_Dyn_Iter> Elf_Dyn_Range;<br>
typedef ELFEntityIterator<const Elf_Rela> Elf_Rela_Iter;<br>
@@ -176,6 +178,7 @@ private:<br>
const Elf_Shdr *dot_symtab_sec = nullptr; // Symbol table section.<br>
StringRef DynSymStrTab; // Dynnamic symbol string table.<br>
const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section.<br>
+ const Elf_Hash *HashTable = nullptr;<br>
<br>
const Elf_Shdr *SymbolTableSectionHeaderIndex = nullptr;<br>
DenseMap<const Elf_Sym *, ELF::Elf64_Word> ExtendedSymbolTable;<br>
@@ -229,6 +232,8 @@ private:<br>
void LoadVersionNeeds(const Elf_Shdr *ec) const;<br>
void LoadVersionMap() const;<br>
<br>
+ void scanDynamicTable();<br>
+<br>
public:<br>
template<typename T><br>
const T *getEntry(uint32_t Section, uint32_t Entry) const;<br>
@@ -237,6 +242,7 @@ public:<br>
<br>
const Elf_Shdr *getDotSymtabSec() const { return dot_symtab_sec; }<br>
const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; }<br>
+ const Elf_Hash *getHashTable() const { return HashTable; }<br>
<br>
ErrorOr<StringRef> getStringTable(const Elf_Shdr *Section) const;<br>
const char *getDynamicString(uintX_t Offset) const;<br>
@@ -578,8 +584,10 @@ ELFFile<ELFT>::ELFFile(StringRef Object,<br>
<br>
Header = reinterpret_cast<const Elf_Ehdr *>(base());<br>
<br>
- if (Header->e_shoff == 0)<br>
+ if (Header->e_shoff == 0) {<br>
+ scanDynamicTable();<br>
return;<br>
+ }<br>
<br>
const uint64_t SectionTableOffset = Header->e_shoff;<br>
<br>
@@ -604,6 +612,13 @@ ELFFile<ELFT>::ELFFile(StringRef Object,<br>
<br>
for (const Elf_Shdr &Sec : sections()) {<br>
switch (Sec.sh_type) {<br>
+ case ELF::SHT_HASH:<br>
+ if (HashTable) {<br>
+ EC = object_error::parse_failed;<br>
+ return;<br>
+ }<br>
+ HashTable = reinterpret_cast<const Elf_Hash *>(base() + Sec.sh_offset);<br>
+ break;<br>
case ELF::SHT_SYMTAB_SHNDX:<br>
if (SymbolTableSectionHeaderIndex) {<br>
// More than one .symtab_shndx!<br>
@@ -701,7 +716,21 @@ ELFFile<ELFT>::ELFFile(StringRef Object,<br>
}<br>
}<br>
<br>
- // Scan program headers.<br>
+ scanDynamicTable();<br>
+<br>
+ EC = std::error_code();<br>
+}<br>
+<br>
+template <class ELFT><br>
+void ELFFile<ELFT>::scanDynamicTable() {<br>
+ // Build load-address to file-offset map.<br>
+ typedef typename IntervalMap<<br>
+ uintX_t, uintptr_t,<br>
+ IntervalMapImpl::NodeSizer<uintX_t, uintptr_t>::LeafSize,<br>
+ IntervalMapHalfOpenInfo<uintX_t>> LoadMapT;<br>
+ LoadMapT::Allocator Alloc;<br>
+ LoadMapT LoadMap(Alloc);<br>
+<br>
for (Elf_Phdr_Iter PhdrI = program_header_begin(),<br>
PhdrE = program_header_end();<br>
PhdrI != PhdrE; ++PhdrI) {<br>
@@ -709,34 +738,36 @@ ELFFile<ELFT>::ELFFile(StringRef Object,<br>
DynamicRegion.Addr = base() + PhdrI->p_offset;<br>
DynamicRegion.Size = PhdrI->p_filesz;<br>
DynamicRegion.EntSize = sizeof(Elf_Dyn);<br>
- break;<br>
+ continue;<br>
}<br>
+ if (PhdrI->p_type != ELF::PT_LOAD)<br>
+ continue;<br>
+ if (PhdrI->p_filesz == 0)<br>
+ continue;<br>
+ LoadMap.insert(PhdrI->p_vaddr, PhdrI->p_vaddr + PhdrI->p_filesz,<br>
+ PhdrI->p_offset);<br>
}<br>
<br>
- // Scan dynamic table.<br>
+ auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * {<br>
+ auto I = LoadMap.find(VAddr);<br>
+ if (I == LoadMap.end())<br>
+ return nullptr;<br>
+ return base() + I.value() + (VAddr - I.start());<br>
+ };<br>
+<br>
for (Elf_Dyn_Iter DynI = dynamic_table_begin(), DynE = dynamic_table_end();<br>
DynI != DynE; ++DynI) {<br>
switch (DynI->d_tag) {<br>
- case ELF::DT_RELA: {<br>
- uint64_t VBase = 0;<br>
- const uint8_t *FBase = nullptr;<br>
- for (Elf_Phdr_Iter PhdrI = program_header_begin(),<br>
- PhdrE = program_header_end();<br>
- PhdrI != PhdrE; ++PhdrI) {<br>
- if (PhdrI->p_type != ELF::PT_LOAD)<br>
- continue;<br>
- if (DynI->getPtr() >= PhdrI->p_vaddr &&<br>
- DynI->getPtr() < PhdrI->p_vaddr + PhdrI->p_memsz) {<br>
- VBase = PhdrI->p_vaddr;<br>
- FBase = base() + PhdrI->p_offset;<br>
- break;<br>
- }<br>
- }<br>
- if (!VBase)<br>
- return;<br>
- DynRelaRegion.Addr = FBase + DynI->getPtr() - VBase;<br>
+ case ELF::DT_HASH:<br>
+ if (HashTable)<br>
+ continue;<br>
+ HashTable =<br>
+ reinterpret_cast<const Elf_Hash *>(toMappedAddr(DynI->getPtr()));<br>
+ break;<br>
+ case ELF::DT_RELA:<br>
+ if (!DynRelaRegion.Addr)<br>
+ DynRelaRegion.Addr = toMappedAddr(DynI->getPtr());<br>
break;<br>
- }<br>
case ELF::DT_RELASZ:<br>
DynRelaRegion.Size = DynI->getVal();<br>
break;<br>
@@ -744,8 +775,6 @@ ELFFile<ELFT>::ELFFile(StringRef Object,<br>
DynRelaRegion.EntSize = DynI->getVal();<br>
}<br>
}<br>
-<br>
- EC = std::error_code();<br>
}<br>
<br>
template <class ELFT><br>
<br>
Modified: llvm/trunk/include/llvm/Object/ELFTypes.h<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_include_llvm_Object_ELFTypes.h-3Frev-3D241765-26r1-3D241764-26r2-3D241765-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=UtQxE0-VNFK75WWnQdSO4HpXT1LjCGDOo_9WnJrGFGw&s=_yh5en8nTmmaIfjM8kXBfoKHgVP7RP46UdSJBXFH3LQ&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/ELFTypes.h?rev=241765&r1=241764&r2=241765&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Object/ELFTypes.h (original)<br>
+++ llvm/trunk/include/llvm/Object/ELFTypes.h Wed Jul 8 19:21:06 2015<br>
@@ -10,6 +10,7 @@<br>
#ifndef LLVM_OBJECT_ELFTYPES_H<br>
#define LLVM_OBJECT_ELFTYPES_H<br>
<br>
+#include "llvm/ADT/ArrayRef.h"<br>
#include "llvm/Object/Error.h"<br>
#include "llvm/Support/DataTypes.h"<br>
#include "llvm/Support/ELF.h"<br>
@@ -463,6 +464,23 @@ struct Elf_Phdr_Impl<ELFType<TargetEndia<br>
Elf_Xword p_align; // Segment alignment constraint<br>
};<br>
<br>
+// ELFT needed for endianess.<br>
+template <class ELFT><br>
+struct Elf_Hash {<br>
+ LLVM_ELF_IMPORT_TYPES_ELFT(ELFT);<br>
+ Elf_Word nbucket;<br>
+ Elf_Word nchain;<br>
+<br>
+ ArrayRef<const Elf_Word> buckets() const {<br>
+ return ArrayRef<const Elf_Word>(&nbucket + 2, &nbucket + 2 + nbucket);<br>
+ }<br>
+<br>
+ ArrayRef<const Elf_Word> chains() const {<br>
+ return ArrayRef<const Elf_Word>(&nbucket + 2 + nbucket,<br>
+ &nbucket + 2 + nbucket + nchain);<br>
+ }<br>
+};<br>
+<br>
// MIPS .reginfo section<br>
template <class ELFT><br>
struct Elf_Mips_RegInfo;<br>
<br>
Added: llvm/trunk/test/Object/Inputs/no-section-table.so<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_test_Object_Inputs_no-2Dsection-2Dtable.so-3Frev-3D241765-26view-3Dauto&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=UtQxE0-VNFK75WWnQdSO4HpXT1LjCGDOo_9WnJrGFGw&s=UfqoLNQO11n-3se3pjPMidT_u_YKjsUTSf6QcEJLvAo&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/no-section-table.so?rev=241765&view=auto</a><br>
==============================================================================<br>
Binary files llvm/trunk/test/Object/Inputs/no-section-table.so (added) and llvm/trunk/test/Object/Inputs/no-section-table.so Wed Jul 8 19:21:06 2015 differ<br>
<br>
Added: llvm/trunk/test/Object/no-section-table.test<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_test_Object_no-2Dsection-2Dtable.test-3Frev-3D241765-26view-3Dauto&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=UtQxE0-VNFK75WWnQdSO4HpXT1LjCGDOo_9WnJrGFGw&s=uQbu5aYZgLJ1P23Bq5xAHgV_uk_xdayG1_JWS9xw-f4&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/no-section-table.test?rev=241765&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Object/no-section-table.test (added)<br>
+++ llvm/trunk/test/Object/no-section-table.test Wed Jul 8 19:21:06 2015<br>
@@ -0,0 +1,8 @@<br>
+RUN: llvm-readobj %p/Inputs/no-section-table.so -hash-table | FileCheck %s<br>
+<br>
+CHECK: HashTable {<br>
+CHECK: Num Buckets: 3<br>
+CHECK: Num Chains: 13<br>
+CHECK: Buckets: [12, 10, 11]<br>
+CHECK: Chains: [0, 0, 0, 0, 2, 3, 4, 0, 7, 5, 6, 8, 9]<br>
+CHECK: }<br>
<br>
Modified: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_tools_llvm-2Dreadobj_ELFDumper.cpp-3Frev-3D241765-26r1-3D241764-26r2-3D241765-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=UtQxE0-VNFK75WWnQdSO4HpXT1LjCGDOo_9WnJrGFGw&s=zbXhwSeW1eTP0vQboSjP2sj-VA4PcxLluvMJwbe2XHw&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ELFDumper.cpp?rev=241765&r1=241764&r2=241765&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp (original)<br>
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp Wed Jul 8 19:21:06 2015<br>
@@ -56,6 +56,7 @@ public:<br>
void printDynamicTable() override;<br>
void printNeededLibraries() override;<br>
void printProgramHeaders() override;<br>
+ void printHashTable() override;<br>
<br>
void printAttributes() override;<br>
void printMipsPLTGOT() override;<br>
@@ -1119,6 +1120,18 @@ void ELFDumper<ELFT>::printProgramHeader<br>
}<br>
}<br>
<br>
+template <typename ELFT><br>
+void ELFDumper<ELFT>::printHashTable() {<br>
+ DictScope D(W, "HashTable");<br>
+ auto HT = Obj->getHashTable();<br>
+ if (!HT)<br>
+ return;<br>
+ W.printNumber("Num Buckets", HT->nbucket);<br>
+ W.printNumber("Num Chains", HT->nchain);<br>
+ W.printList("Buckets", HT->buckets());<br>
+ W.printList("Chains", HT->chains());<br>
+}<br>
+<br>
template <class ELFT><br>
void ELFDumper<ELFT>::printAttributes() {<br>
W.startLine() << "Attributes not implemented.\n";<br>
<br>
Modified: llvm/trunk/tools/llvm-readobj/ObjDumper.h<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_tools_llvm-2Dreadobj_ObjDumper.h-3Frev-3D241765-26r1-3D241764-26r2-3D241765-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=UtQxE0-VNFK75WWnQdSO4HpXT1LjCGDOo_9WnJrGFGw&s=TRvhhClXhJiU8e46dRlctaho7yftLo0y07w2yDYxh30&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ObjDumper.h?rev=241765&r1=241764&r2=241765&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-readobj/ObjDumper.h (original)<br>
+++ llvm/trunk/tools/llvm-readobj/ObjDumper.h Wed Jul 8 19:21:06 2015<br>
@@ -37,6 +37,7 @@ public:<br>
virtual void printDynamicTable() { }<br>
virtual void printNeededLibraries() { }<br>
virtual void printProgramHeaders() { }<br>
+ virtual void printHashTable() { }<br>
<br>
// Only implemented for ARM ELF at this time.<br>
virtual void printAttributes() { }<br>
<br>
Modified: llvm/trunk/tools/llvm-readobj/StreamWriter.h<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_tools_llvm-2Dreadobj_StreamWriter.h-3Frev-3D241765-26r1-3D241764-26r2-3D241765-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=UtQxE0-VNFK75WWnQdSO4HpXT1LjCGDOo_9WnJrGFGw&s=LM4ZL2T8BH_8R6wQKMZxTGpbOYIrOl-fwJmQezDWUmk&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/StreamWriter.h?rev=241765&r1=241764&r2=241765&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-readobj/StreamWriter.h (original)<br>
+++ llvm/trunk/tools/llvm-readobj/StreamWriter.h Wed Jul 8 19:21:06 2015<br>
@@ -181,8 +181,8 @@ public:<br>
startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n';<br>
}<br>
<br>
- template <typename T_><br>
- void printList(StringRef Label, const SmallVectorImpl<T_> &List) {<br>
+ template <typename T><br>
+ void printList(StringRef Label, const T &List) {<br>
startLine() << Label << ": [";<br>
bool Comma = false;<br>
for (const auto &Item : List) {<br>
<br>
Modified: llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_tools_llvm-2Dreadobj_llvm-2Dreadobj.cpp-3Frev-3D241765-26r1-3D241764-26r2-3D241765-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=UtQxE0-VNFK75WWnQdSO4HpXT1LjCGDOo_9WnJrGFGw&s=1intY3JBekeiZCDA7jrlI5B0y8Goi1XJeQyDpIkm-wA&e=" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp?rev=241765&r1=241764&r2=241765&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp (original)<br>
+++ llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp Wed Jul 8 19:21:06 2015<br>
@@ -127,6 +127,10 @@ namespace opts {<br>
cl::opt<bool> ProgramHeaders("program-headers",<br>
cl::desc("Display ELF program headers"));<br>
<br>
+ // -hash-table<br>
+ cl::opt<bool> HashTable("hash-table",<br>
+ cl::desc("Display ELF hash table"));<br>
+<br>
// -expand-relocs<br>
cl::opt<bool> ExpandRelocs("expand-relocs",<br>
cl::desc("Expand each shown relocation to multiple lines"));<br>
@@ -300,6 +304,8 @@ static void dumpObject(const ObjectFile<br>
Dumper->printNeededLibraries();<br>
if (opts::ProgramHeaders)<br>
Dumper->printProgramHeaders();<br>
+ if (opts::HashTable)<br>
+ Dumper->printHashTable();<br>
if (Obj->getArch() == llvm::Triple::arm && Obj->isELF())<br>
if (opts::ARMAttributes)<br>
Dumper->printAttributes();<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>