diff options
-rw-r--r-- | bfd/ChangeLog | 12 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 9 | ||||
-rw-r--r-- | bfd/bfd.c | 9 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 10 | ||||
-rw-r--r-- | bfd/elf.c | 12 | ||||
-rw-r--r-- | bfd/libpei.h | 4 | ||||
-rw-r--r-- | bfd/peXXigen.c | 2 | ||||
-rw-r--r-- | bfd/peicode.h | 100 | ||||
-rw-r--r-- | gdb/ChangeLog | 13 | ||||
-rw-r--r-- | gdb/build-id.c | 21 | ||||
-rw-r--r-- | gdb/build-id.h | 2 | ||||
-rw-r--r-- | gdb/coffread.c | 6 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 2 | ||||
-rw-r--r-- | gdb/python/py-objfile.c | 7 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/sepdebug.exp | 12 | ||||
-rw-r--r-- | gdb/testsuite/lib/future.exp | 11 | ||||
-rw-r--r-- | gdb/testsuite/lib/gdb.exp | 53 |
19 files changed, 231 insertions, 66 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index ef760d1..886da5b 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,15 @@ +2015-06-10 Jon Turney <jon.turney@dronecode.org.uk> + + * elf-bfd.h : Remove struct elf_build_id. + * bfd.c : Add struct bfd_build_id. + * bfd-in2.h: Regenerate. + * elf.c (elfobj_grok_gnu_build_id): Update to use bfd_build_id. + * libpei.h: Add protoype and macros for + bfd_XXi_slurp_codeview_record. + * peXXigen.c (_bfd_XXi_slurp_codeview_record): Make public + * peicode.h (pe_bfd_read_buildid): Add. + (pe_bfd_object_p): Use pe_bfd_read_buildid(). + 2015-06-15 Renlin Li <renlin.li@arm.com> * reloc.c (BFD_RELOC_AARCH64_LD64_GOTOFF_LO15): New entry. diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 60b7a24..dfffe3c 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -6326,6 +6326,12 @@ enum bfd_plugin_format bfd_plugin_no = 2 }; +struct bfd_build_id + { + size_t size; + bfd_byte data[1]; + }; + struct bfd { /* The filename the application opened the BFD with. */ @@ -6610,6 +6616,9 @@ struct bfd struct objalloc *, but we use void * to avoid requiring the inclusion of objalloc.h. */ void *memory; + + /* For input BFDs, the build ID, if the object has one. */ + const struct bfd_build_id *build_id; }; /* See note beside bfd_set_section_userdata. */ @@ -51,6 +51,12 @@ CODE_FRAGMENT . bfd_plugin_no = 2 . }; . +.struct bfd_build_id +. { +. size_t size; +. bfd_byte data[1]; +. }; +. .struct bfd .{ . {* The filename the application opened the BFD with. *} @@ -335,6 +341,9 @@ CODE_FRAGMENT . struct objalloc *, but we use void * to avoid requiring the inclusion . of objalloc.h. *} . void *memory; +. +. {* For input BFDs, the build ID, if the object has one. *} +. const struct bfd_build_id *build_id; .}; . .{* See note beside bfd_set_section_userdata. *} diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 9807fe7..1127b7e 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1563,13 +1563,6 @@ struct sdt_note bfd_byte data[1]; }; -/* NT_GNU_BUILD_ID note type info for input BFDs. */ -struct elf_build_id -{ - size_t size; - bfd_byte data[1]; -}; - /* tdata information grabbed from an elf core file. */ struct core_elf_obj_tdata { @@ -1704,9 +1697,6 @@ struct elf_obj_tdata obj_attribute known_obj_attributes[2][NUM_KNOWN_OBJ_ATTRIBUTES]; obj_attribute_list *other_obj_attributes[2]; - /* NT_GNU_BUILD_ID note type. */ - struct elf_build_id *build_id; - /* Linked-list containing information about every Systemtap section found in the object file. Each section corresponds to one entry in the list. */ @@ -9116,18 +9116,18 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) static bfd_boolean elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note) { - struct elf_obj_tdata *t; + struct bfd_build_id* build_id; if (note->descsz == 0) return FALSE; - t = elf_tdata (abfd); - t->build_id = bfd_alloc (abfd, sizeof (*t->build_id) - 1 + note->descsz); - if (t->build_id == NULL) + build_id = bfd_alloc (abfd, sizeof (struct bfd_build_id) - 1 + note->descsz); + if (build_id == NULL) return FALSE; - t->build_id->size = note->descsz; - memcpy (t->build_id->data, note->descdata, note->descsz); + build_id->size = note->descsz; + memcpy (build_id->data, note->descdata, note->descsz); + abfd->build_id = build_id; return TRUE; } diff --git a/bfd/libpei.h b/bfd/libpei.h index d19a3b2..a6f3da0 100644 --- a/bfd/libpei.h +++ b/bfd/libpei.h @@ -238,6 +238,7 @@ #define _bfd_XXi_swap_debugdir_in _bfd_pex64i_swap_debugdir_in #define _bfd_XXi_swap_debugdir_out _bfd_pex64i_swap_debugdir_out #define _bfd_XXi_write_codeview_record _bfd_pex64i_write_codeview_record +#define _bfd_XXi_slurp_codeview_record _bfd_pex64i_slurp_codeview_record #elif defined COFF_WITH_pep @@ -272,6 +273,7 @@ #define _bfd_XXi_swap_debugdir_in _bfd_pepi_swap_debugdir_in #define _bfd_XXi_swap_debugdir_out _bfd_pepi_swap_debugdir_out #define _bfd_XXi_write_codeview_record _bfd_pepi_write_codeview_record +#define _bfd_XXi_slurp_codeview_record _bfd_pepi_slurp_codeview_record #else /* !COFF_WITH_pep */ @@ -306,6 +308,7 @@ #define _bfd_XXi_swap_debugdir_in _bfd_pei_swap_debugdir_in #define _bfd_XXi_swap_debugdir_out _bfd_pei_swap_debugdir_out #define _bfd_XXi_write_codeview_record _bfd_pei_write_codeview_record +#define _bfd_XXi_slurp_codeview_record _bfd_pei_slurp_codeview_record #endif /* !COFF_WITH_pep */ @@ -351,6 +354,7 @@ bfd_boolean _bfd_XXi_final_link_postscript (bfd *, struct coff_final_link_info * void _bfd_XXi_swap_debugdir_in (bfd *, void *, void *); unsigned _bfd_XXi_swap_debugdir_out (bfd *, void *, void *); unsigned _bfd_XXi_write_codeview_record (bfd *, file_ptr, CODEVIEW_INFO *); +CODEVIEW_INFO * _bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length, CODEVIEW_INFO *cvinfo); /* The following are needed only for ONE of pe or pei, but don't otherwise vary; peicode.h fixes up ifdefs but we provide the diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c index c897c64..d209b50 100644 --- a/bfd/peXXigen.c +++ b/bfd/peXXigen.c @@ -1140,7 +1140,7 @@ _bfd_XXi_swap_debugdir_out (bfd * abfd, void * inp, void * extp) return sizeof (struct external_IMAGE_DEBUG_DIRECTORY); } -static CODEVIEW_INFO * +CODEVIEW_INFO * _bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length, CODEVIEW_INFO *cvinfo) { char buffer[256+1]; diff --git a/bfd/peicode.h b/bfd/peicode.h index 200ef5e..06bcaa9 100644 --- a/bfd/peicode.h +++ b/bfd/peicode.h @@ -1255,6 +1255,87 @@ pe_ILF_object_p (bfd * abfd) return abfd->xvec; } +static void +pe_bfd_read_buildid(bfd *abfd) +{ + pe_data_type *pe = pe_data (abfd); + struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; + asection *section; + bfd_byte *data = 0; + bfd_size_type dataoff; + unsigned int i; + + bfd_vma addr = extra->DataDirectory[PE_DEBUG_DATA].VirtualAddress; + bfd_size_type size = extra->DataDirectory[PE_DEBUG_DATA].Size; + + if (size == 0) + return; + + addr += extra->ImageBase; + + /* Search for the section containing the DebugDirectory */ + for (section = abfd->sections; section != NULL; section = section->next) + { + if ((addr >= section->vma) && (addr < (section->vma + section->size))) + break; + } + + if (section == NULL) + { + return; + } + else if (!(section->flags & SEC_HAS_CONTENTS)) + { + return; + } + + dataoff = addr - section->vma; + + /* Read the whole section. */ + if (!bfd_malloc_and_get_section (abfd, section, &data)) + { + if (data != NULL) + free (data); + return; + } + + /* Search for a CodeView entry in the DebugDirectory */ + for (i = 0; i < size / sizeof (struct external_IMAGE_DEBUG_DIRECTORY); i++) + { + struct external_IMAGE_DEBUG_DIRECTORY *ext + = &((struct external_IMAGE_DEBUG_DIRECTORY *)(data + dataoff))[i]; + struct internal_IMAGE_DEBUG_DIRECTORY idd; + + _bfd_XXi_swap_debugdir_in (abfd, ext, &idd); + + if (idd.Type == PE_IMAGE_DEBUG_TYPE_CODEVIEW) + { + char buffer[256 + 1]; + CODEVIEW_INFO *cvinfo = (CODEVIEW_INFO *) buffer; + + /* + The debug entry doesn't have to have to be in a section, in which + case AddressOfRawData is 0, so always use PointerToRawData. + */ + if (_bfd_XXi_slurp_codeview_record (abfd, + (file_ptr) idd.PointerToRawData, + idd.SizeOfData, cvinfo)) + { + struct bfd_build_id* build_id = bfd_alloc(abfd, + sizeof(struct bfd_build_id) + cvinfo->SignatureLength); + if (build_id) + { + build_id->size = cvinfo->SignatureLength; + memcpy(build_id->data, cvinfo->Signature, + cvinfo->SignatureLength); + abfd->build_id = build_id; + } + } + break; + } + } +} + static const bfd_target * pe_bfd_object_p (bfd * abfd) { @@ -1265,6 +1346,7 @@ pe_bfd_object_p (bfd * abfd) struct internal_aouthdr internal_a; file_ptr opt_hdr_size; file_ptr offset; + const bfd_target *result; /* Detect if this a Microsoft Import Library Format element. */ /* First read the beginning of the header. */ @@ -1358,10 +1440,20 @@ pe_bfd_object_p (bfd * abfd) return NULL; } - return coff_real_object_p (abfd, internal_f.f_nscns, &internal_f, - (opt_hdr_size != 0 - ? &internal_a - : (struct internal_aouthdr *) NULL)); + + result = coff_real_object_p (abfd, internal_f.f_nscns, &internal_f, + (opt_hdr_size != 0 + ? &internal_a + : (struct internal_aouthdr *) NULL)); + + + if (result) + { + /* Now the whole header has been processed, see if there is a build-id */ + pe_bfd_read_buildid(abfd); + } + + return result; } #define coff_object_p pe_bfd_object_p diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4769bad..fdf519a 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2015-06-10 Jon Turney <jon.turney@dronecode.org.uk> + + * build-id.c: Don't include elf-bfd.h. + (build_id_bfd_get): Use bfd_build_id. + (build_id_verify): Ditto. + * build-id.h: Ditto. + (find_separate_debug_file_by_buildid): Ditto. + * python/py-objfile.c: Don't include elf-bfd.h. + (objfpy_get_build_id) Use bfd_build_id. + (objfpy_build_id_matches, objfpy_lookup_objfile_by_build_id): Ditto. + * coffread.c: Include build-id.h. + (coff_symfile_read): Try find_separate_debug_file_by_buildid. + 2015-06-03 Jon Turney <jon.turney@dronecode.org.uk> * windows-nat.c (do_windows_fetch_inferior_registers) diff --git a/gdb/build-id.c b/gdb/build-id.c index 8f7bbb4..ebf9f45 100644 --- a/gdb/build-id.c +++ b/gdb/build-id.c @@ -19,7 +19,6 @@ #include "defs.h" #include "bfd.h" -#include "elf-bfd.h" #include "gdb_bfd.h" #include "build-id.h" #include "gdb_vecs.h" @@ -30,19 +29,17 @@ /* See build-id.h. */ -const struct elf_build_id * +const struct bfd_build_id * build_id_bfd_get (bfd *abfd) { - if (!bfd_check_format (abfd, bfd_object) - || bfd_get_flavour (abfd) != bfd_target_elf_flavour - /* Although this is ELF_specific, it is safe to do in generic - code because it does not rely on any ELF-specific symbols at - link time, and if the ELF code is not available in BFD, then - ABFD will not have the ELF flavour. */ - || elf_tdata (abfd)->build_id == NULL) + if (!bfd_check_format (abfd, bfd_object)) return NULL; - return elf_tdata (abfd)->build_id; + if (abfd->build_id != NULL) + return abfd->build_id; + + /* No build-id */ + return NULL; } /* See build-id.h. */ @@ -50,7 +47,7 @@ build_id_bfd_get (bfd *abfd) int build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check) { - const struct elf_build_id *found; + const struct bfd_build_id *found; int retval = 0; found = build_id_bfd_get (abfd); @@ -139,7 +136,7 @@ build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id) char * find_separate_debug_file_by_buildid (struct objfile *objfile) { - const struct elf_build_id *build_id; + const struct bfd_build_id *build_id; build_id = build_id_bfd_get (objfile->obfd); if (build_id != NULL) diff --git a/gdb/build-id.h b/gdb/build-id.h index f77dda2..bea761b 100644 --- a/gdb/build-id.h +++ b/gdb/build-id.h @@ -22,7 +22,7 @@ /* Locate NT_GNU_BUILD_ID from ABFD and return its content. */ -extern const struct elf_build_id *build_id_bfd_get (bfd *abfd); +extern const struct bfd_build_id *build_id_bfd_get (bfd *abfd); /* Return true if ABFD has NT_GNU_BUILD_ID matching the CHECK value. Otherwise, issue a warning and return false. */ diff --git a/gdb/coffread.c b/gdb/coffread.c index 3b5a968..7722cdb 100644 --- a/gdb/coffread.c +++ b/gdb/coffread.c @@ -41,6 +41,7 @@ #include "coff-pe-read.h" #include "psymtab.h" +#include "build-id.h" extern void _initialize_coffread (void); @@ -738,7 +739,10 @@ coff_symfile_read (struct objfile *objfile, int symfile_flags) { char *debugfile; - debugfile = find_separate_debug_file_by_debuglink (objfile); + debugfile = find_separate_debug_file_by_buildid (objfile); + + if (debugfile == NULL) + debugfile = find_separate_debug_file_by_debuglink (objfile); make_cleanup (xfree, debugfile); if (debugfile) diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 4d42a37..53e6689 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2015-06-10 Jon Turney <jon.turney@dronecode.org.uk> + + * gdb.texinfo (Separate Debug Files): Document that PE is also + supported. + 2015-06-13 Andrew Burgess <andrew.burgess@embecosm.com> * gdb.texinfo (TUI Commands): Bring all 'tui reg' commands into a diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index faca83e..81e3181 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -18170,7 +18170,7 @@ the executable and the debug file came from the same build. @item The executable contains a @dfn{build ID}, a unique bit string that is also present in the corresponding debug info file. (This is supported -only on some operating systems, notably those which use the ELF format +only on some operating systems, when using the ELF or PE file formats for binary files and the @sc{gnu} Binutils.) For more details about this feature, see the description of the @option{--build-id} command-line option in @ref{Options, , Command Line Options, ld.info, diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c index c9528c3..5dc9ae6 100644 --- a/gdb/python/py-objfile.c +++ b/gdb/python/py-objfile.c @@ -23,7 +23,6 @@ #include "objfiles.h" #include "language.h" #include "build-id.h" -#include "elf-bfd.h" #include "symtab.h" typedef struct @@ -134,7 +133,7 @@ objfpy_get_build_id (PyObject *self, void *closure) { objfile_object *obj = (objfile_object *) self; struct objfile *objfile = obj->objfile; - const struct elf_build_id *build_id = NULL; + const struct bfd_build_id *build_id = NULL; OBJFPY_REQUIRE_VALID (obj); @@ -484,7 +483,7 @@ objfpy_build_id_ok (const char *string) It is assumed that objfpy_build_id_ok (string) returns TRUE. */ static int -objfpy_build_id_matches (const struct elf_build_id *build_id, +objfpy_build_id_matches (const struct bfd_build_id *build_id, const char *string) { size_t i; @@ -542,7 +541,7 @@ objfpy_lookup_objfile_by_build_id (const char *build_id) ALL_OBJFILES (objfile) { - const struct elf_build_id *obfd_build_id; + const struct bfd_build_id *obfd_build_id; if (objfile->obfd == NULL) continue; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index e01f883..c564c66 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2015-06-10 Jon Turney <jon.turney@dronecode.org.uk> + + * gdb.base/sepdebug.exp: Add EXEEXT where needed. + * lib/gdb.exp (get_build_id): Teach how to extract build-id from a + PE file. + * lib/future.exp (gdb_find_objdump): Add gdb_find_objdump. + 2015-06-12 Antoine Tremblay <antoine.tremblay@ericsson.com> PR breakpoints/16465 diff --git a/gdb/testsuite/gdb.base/sepdebug.exp b/gdb/testsuite/gdb.base/sepdebug.exp index 3194377..c363be4 100644 --- a/gdb/testsuite/gdb.base/sepdebug.exp +++ b/gdb/testsuite/gdb.base/sepdebug.exp @@ -42,7 +42,7 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb # the name of a debuginfo only file. This file will be stored in the # gdb.base/ subdirectory. -if [gdb_gnu_strip_debug $binfile] { +if [gdb_gnu_strip_debug $binfile$EXEEXT] { # check that you have a recent version of strip and objcopy installed unsupported "cannot produce separate debug info files" return -1 @@ -60,7 +60,7 @@ set new_name [standard_output_file ${testfile}${EXEEXT}] remote_exec build "rm -rf [file dirname $new_name]" remote_exec build "mkdir [file dirname $new_name]" -remote_exec build "ln -s ${binfile} $new_name" +remote_exec build "ln -s ${binfile}${EXEEXT} $new_name" clean_restart ${testfile}${EXEEXT} if { $gdb_file_cmd_debug_info != "debug" } then { fail "No debug information found." @@ -716,10 +716,10 @@ proc test_different_dir {type test_different_dir xfail} { # the "set debug-file-directory" command. set different_dir [standard_output_file ${testfile}.dir] -set debugfile "${different_dir}/[standard_output_file ${testfile}.debug]" +set debugfile "${different_dir}/[standard_output_file ${testfile}${EXEEXT}.debug]" remote_exec build "rm -rf $different_dir" remote_exec build "mkdir -p [file dirname $debugfile]" -remote_exec build "mv -f [standard_output_file ${testfile}.debug] $debugfile" +remote_exec build "mv -f [standard_output_file ${testfile}${EXEEXT}.debug] $debugfile" test_different_dir debuglink $different_dir 0 @@ -727,7 +727,7 @@ test_different_dir debuglink $different_dir 0 # Test CRC mismatch is reported. if {[build_executable sepdebug.exp sepdebug2 sepdebug2.c debug] != -1 - && ![gdb_gnu_strip_debug [standard_output_file sepdebug2]]} { + && ![gdb_gnu_strip_debug [standard_output_file sepdebug2]$EXEEXT]} { remote_exec build "cp ${debugfile} [standard_output_file sepdebug2.debug]" @@ -743,7 +743,7 @@ if {[build_executable sepdebug.exp sepdebug2 sepdebug2.c debug] != -1 # NT_GNU_BUILD_ID / .note.gnu.build-id test: -set build_id_debug_filename [build_id_debug_filename_get $binfile] +set build_id_debug_filename [build_id_debug_filename_get $binfile$EXEEXT] if ![string compare $build_id_debug_filename ""] then { unsupported "build-id is not supported by the compiler" diff --git a/gdb/testsuite/lib/future.exp b/gdb/testsuite/lib/future.exp index 2fb635b..a27e120 100644 --- a/gdb/testsuite/lib/future.exp +++ b/gdb/testsuite/lib/future.exp @@ -104,6 +104,17 @@ proc gdb_find_objcopy {} { return $objcopy } +# find target objdump +proc gdb_find_objdump {} { + global OBJDUMP_FOR_TARGET + if [info exists OBJDUMP_FOR_TARGET] { + set objdump $OBJDUMP_FOR_TARGET + } else { + set objdump [transform objdump] + } + return $objdump +} + proc gdb_find_readelf {} { global READELF_FOR_TARGET if [info exists READELF_FOR_TARGET] { diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 41797e7..21a4638 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -4539,28 +4539,41 @@ gdb_caching_proc gdb_has_argv0 { # Returns "" if there is none. proc get_build_id { filename } { - set tmp [standard_output_file "${filename}-tmp"] - set objcopy_program [gdb_find_objcopy] - - set result [catch "exec $objcopy_program -j .note.gnu.build-id -O binary $filename $tmp" output] - verbose "result is $result" - verbose "output is $output" - if {$result == 1} { - return "" + if { ([istarget "*-*-mingw*"] + || [istarget *-*-cygwin*]) } { + set objdump_program [gdb_find_objdump] + set result [catch {set data [exec $objdump_program -p $filename | grep signature | cut "-d " -f4]} output] + verbose "result is $result" + verbose "output is $output" + if {$result == 1} { + return "" + } + return $data } - set fi [open $tmp] - fconfigure $fi -translation binary - # Skip the NOTE header. - read $fi 16 - set data [read $fi] - close $fi - file delete $tmp - if ![string compare $data ""] then { - return "" + else + { + set tmp [standard_output_file "${filename}-tmp"] + set objcopy_program [gdb_find_objcopy] + set result [catch "exec $objcopy_program -j .note.gnu.build-id -O binary $filename $tmp" output] + verbose "result is $result" + verbose "output is $output" + if {$result == 1} { + return "" + } + set fi [open $tmp] + fconfigure $fi -translation binary + # Skip the NOTE header. + read $fi 16 + set data [read $fi] + close $fi + file delete $tmp + if ![string compare $data ""] then { + return "" + } + # Convert it to hex. + binary scan $data H* data + return $data } - # Convert it to hex. - binary scan $data H* data - return $data } # Return the build-id hex string (usually 160 bits as 40 hex characters) |