1*eb8dc403SDave CobbleyUpstream-Status: Inappropriate [embedded specific] 2*eb8dc403SDave Cobbley 3*eb8dc403SDave CobbleyWe run the ldconfig in the cross fashion. make the code bitsize aware so that 4*eb8dc403SDave Cobbleywe can cross build ldconfig cache for various architectures. 5*eb8dc403SDave Cobbley 6*eb8dc403SDave CobbleyRichard Purdie <richard.purdie@linuxfoundation.org> 2009/05/19 7*eb8dc403SDave CobbleyNitin A Kamble <nitin.a.kamble@intel.com> 2009/03/29 8*eb8dc403SDave Cobbley 9*eb8dc403SDave CobbleyIndex: ldconfig-native-2.12.1/readelflib.c 10*eb8dc403SDave Cobbley=================================================================== 11*eb8dc403SDave Cobbley--- ldconfig-native-2.12.1.orig/readelflib.c 12*eb8dc403SDave Cobbley+++ ldconfig-native-2.12.1/readelflib.c 13*eb8dc403SDave Cobbley@@ -40,39 +40,212 @@ do \ 14*eb8dc403SDave Cobbley 15*eb8dc403SDave Cobbley /* Returns 0 if everything is ok, != 0 in case of error. */ 16*eb8dc403SDave Cobbley int 17*eb8dc403SDave Cobbley-process_elf_file (const char *file_name, const char *lib, int *flag, 18*eb8dc403SDave Cobbley+process_elf_file32 (const char *file_name, const char *lib, int *flag, 19*eb8dc403SDave Cobbley unsigned int *osversion, char **soname, void *file_contents, 20*eb8dc403SDave Cobbley size_t file_length) 21*eb8dc403SDave Cobbley { 22*eb8dc403SDave Cobbley int i; 23*eb8dc403SDave Cobbley unsigned int j; 24*eb8dc403SDave Cobbley- ElfW(Addr) loadaddr; 25*eb8dc403SDave Cobbley+ Elf32_Addr loadaddr; 26*eb8dc403SDave Cobbley unsigned int dynamic_addr; 27*eb8dc403SDave Cobbley size_t dynamic_size; 28*eb8dc403SDave Cobbley char *program_interpreter; 29*eb8dc403SDave Cobbley 30*eb8dc403SDave Cobbley- ElfW(Ehdr) *elf_header; 31*eb8dc403SDave Cobbley- ElfW(Phdr) *elf_pheader, *segment; 32*eb8dc403SDave Cobbley- ElfW(Dyn) *dynamic_segment, *dyn_entry; 33*eb8dc403SDave Cobbley+ Elf32_Ehdr *elf_header; 34*eb8dc403SDave Cobbley+ Elf32_Phdr *elf_pheader, *segment; 35*eb8dc403SDave Cobbley+ Elf32_Dyn *dynamic_segment, *dyn_entry; 36*eb8dc403SDave Cobbley char *dynamic_strings; 37*eb8dc403SDave Cobbley 38*eb8dc403SDave Cobbley- elf_header = (ElfW(Ehdr) *) file_contents; 39*eb8dc403SDave Cobbley+ elf_header = (Elf32_Ehdr *) file_contents; 40*eb8dc403SDave Cobbley *osversion = 0; 41*eb8dc403SDave Cobbley 42*eb8dc403SDave Cobbley- if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS)) 43*eb8dc403SDave Cobbley+ if (elf_header->e_type != ET_DYN) 44*eb8dc403SDave Cobbley { 45*eb8dc403SDave Cobbley- if (opt_verbose) 46*eb8dc403SDave Cobbley+ error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name, 47*eb8dc403SDave Cobbley+ elf_header->e_type); 48*eb8dc403SDave Cobbley+ return 1; 49*eb8dc403SDave Cobbley+ } 50*eb8dc403SDave Cobbley+ 51*eb8dc403SDave Cobbley+ /* Get information from elf program header. */ 52*eb8dc403SDave Cobbley+ elf_pheader = (Elf32_Phdr *) (elf_header->e_phoff + file_contents); 53*eb8dc403SDave Cobbley+ check_ptr (elf_pheader); 54*eb8dc403SDave Cobbley+ 55*eb8dc403SDave Cobbley+ /* The library is an elf library, now search for soname and 56*eb8dc403SDave Cobbley+ libc5/libc6. */ 57*eb8dc403SDave Cobbley+ *flag = FLAG_ELF; 58*eb8dc403SDave Cobbley+ 59*eb8dc403SDave Cobbley+ loadaddr = -1; 60*eb8dc403SDave Cobbley+ dynamic_addr = 0; 61*eb8dc403SDave Cobbley+ dynamic_size = 0; 62*eb8dc403SDave Cobbley+ program_interpreter = NULL; 63*eb8dc403SDave Cobbley+ for (i = 0, segment = elf_pheader; 64*eb8dc403SDave Cobbley+ i < elf_header->e_phnum; i++, segment++) 65*eb8dc403SDave Cobbley+ { 66*eb8dc403SDave Cobbley+ check_ptr (segment); 67*eb8dc403SDave Cobbley+ 68*eb8dc403SDave Cobbley+ switch (segment->p_type) 69*eb8dc403SDave Cobbley { 70*eb8dc403SDave Cobbley- if (elf_header->e_ident [EI_CLASS] == ELFCLASS32) 71*eb8dc403SDave Cobbley- error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name); 72*eb8dc403SDave Cobbley- else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64) 73*eb8dc403SDave Cobbley- error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name); 74*eb8dc403SDave Cobbley- else 75*eb8dc403SDave Cobbley- error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name); 76*eb8dc403SDave Cobbley+ case PT_LOAD: 77*eb8dc403SDave Cobbley+ if (loadaddr == (Elf32_Addr) -1) 78*eb8dc403SDave Cobbley+ loadaddr = segment->p_vaddr - segment->p_offset; 79*eb8dc403SDave Cobbley+ break; 80*eb8dc403SDave Cobbley+ 81*eb8dc403SDave Cobbley+ case PT_DYNAMIC: 82*eb8dc403SDave Cobbley+ if (dynamic_addr) 83*eb8dc403SDave Cobbley+ error (0, 0, _("more than one dynamic segment\n")); 84*eb8dc403SDave Cobbley+ 85*eb8dc403SDave Cobbley+ dynamic_addr = segment->p_offset; 86*eb8dc403SDave Cobbley+ dynamic_size = segment->p_filesz; 87*eb8dc403SDave Cobbley+ break; 88*eb8dc403SDave Cobbley+ 89*eb8dc403SDave Cobbley+ case PT_INTERP: 90*eb8dc403SDave Cobbley+ program_interpreter = (char *) (file_contents + segment->p_offset); 91*eb8dc403SDave Cobbley+ check_ptr (program_interpreter); 92*eb8dc403SDave Cobbley+ 93*eb8dc403SDave Cobbley+ /* Check if this is enough to classify the binary. */ 94*eb8dc403SDave Cobbley+ for (j = 0; j < sizeof (interpreters) / sizeof (interpreters [0]); 95*eb8dc403SDave Cobbley+ ++j) 96*eb8dc403SDave Cobbley+ if (strcmp (program_interpreter, interpreters[j].soname) == 0) 97*eb8dc403SDave Cobbley+ { 98*eb8dc403SDave Cobbley+ *flag = interpreters[j].flag; 99*eb8dc403SDave Cobbley+ break; 100*eb8dc403SDave Cobbley+ } 101*eb8dc403SDave Cobbley+ break; 102*eb8dc403SDave Cobbley+ 103*eb8dc403SDave Cobbley+ case PT_NOTE: 104*eb8dc403SDave Cobbley+ if (!*osversion && segment->p_filesz >= 32 && segment->p_align >= 4) 105*eb8dc403SDave Cobbley+ { 106*eb8dc403SDave Cobbley+ Elf32_Word *abi_note = (Elf32_Word *) (file_contents 107*eb8dc403SDave Cobbley+ + segment->p_offset); 108*eb8dc403SDave Cobbley+ Elf32_Addr size = segment->p_filesz; 109*eb8dc403SDave Cobbley+ 110*eb8dc403SDave Cobbley+ while (abi_note [0] != 4 || abi_note [1] != 16 111*eb8dc403SDave Cobbley+ || abi_note [2] != 1 112*eb8dc403SDave Cobbley+ || memcmp (abi_note + 3, "GNU", 4) != 0) 113*eb8dc403SDave Cobbley+ { 114*eb8dc403SDave Cobbley+#define ROUND(len) (((len) + sizeof (Elf32_Word)) - 1) & -sizeof (Elf32_Word))) 115*eb8dc403SDave Cobbley+ Elf32_Addr) note_size = 3 * sizeof (Elf32_Word)) 116*eb8dc403SDave Cobbley+ + ROUND (abi_note[0]) 117*eb8dc403SDave Cobbley+ + ROUND (abi_note[1]); 118*eb8dc403SDave Cobbley+ 119*eb8dc403SDave Cobbley+ if (size - 32 < note_size || note_size == 0) 120*eb8dc403SDave Cobbley+ { 121*eb8dc403SDave Cobbley+ size = 0; 122*eb8dc403SDave Cobbley+ break; 123*eb8dc403SDave Cobbley+ } 124*eb8dc403SDave Cobbley+ size -= note_size; 125*eb8dc403SDave Cobbley+ abi_note = (void *) abi_note + note_size; 126*eb8dc403SDave Cobbley+ } 127*eb8dc403SDave Cobbley+ 128*eb8dc403SDave Cobbley+ if (size == 0) 129*eb8dc403SDave Cobbley+ break; 130*eb8dc403SDave Cobbley+ 131*eb8dc403SDave Cobbley+ *osversion = (abi_note [4] << 24) | 132*eb8dc403SDave Cobbley+ ((abi_note [5] & 0xff) << 16) | 133*eb8dc403SDave Cobbley+ ((abi_note [6] & 0xff) << 8) | 134*eb8dc403SDave Cobbley+ (abi_note [7] & 0xff); 135*eb8dc403SDave Cobbley+ } 136*eb8dc403SDave Cobbley+ break; 137*eb8dc403SDave Cobbley+ 138*eb8dc403SDave Cobbley+ default: 139*eb8dc403SDave Cobbley+ break; 140*eb8dc403SDave Cobbley+ } 141*eb8dc403SDave Cobbley+ 142*eb8dc403SDave Cobbley+ } 143*eb8dc403SDave Cobbley+ if (loadaddr == (Elf32_Addr) -1) 144*eb8dc403SDave Cobbley+ { 145*eb8dc403SDave Cobbley+ /* Very strange. */ 146*eb8dc403SDave Cobbley+ loadaddr = 0; 147*eb8dc403SDave Cobbley+ } 148*eb8dc403SDave Cobbley+ 149*eb8dc403SDave Cobbley+ /* Now we can read the dynamic sections. */ 150*eb8dc403SDave Cobbley+ if (dynamic_size == 0) 151*eb8dc403SDave Cobbley+ return 1; 152*eb8dc403SDave Cobbley+ 153*eb8dc403SDave Cobbley+ dynamic_segment = (Elf32_Dyn *) (file_contents + dynamic_addr); 154*eb8dc403SDave Cobbley+ check_ptr (dynamic_segment); 155*eb8dc403SDave Cobbley+ 156*eb8dc403SDave Cobbley+ /* Find the string table. */ 157*eb8dc403SDave Cobbley+ dynamic_strings = NULL; 158*eb8dc403SDave Cobbley+ for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL; 159*eb8dc403SDave Cobbley+ ++dyn_entry) 160*eb8dc403SDave Cobbley+ { 161*eb8dc403SDave Cobbley+ check_ptr (dyn_entry); 162*eb8dc403SDave Cobbley+ if (dyn_entry->d_tag == DT_STRTAB) 163*eb8dc403SDave Cobbley+ { 164*eb8dc403SDave Cobbley+ dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr); 165*eb8dc403SDave Cobbley+ check_ptr (dynamic_strings); 166*eb8dc403SDave Cobbley+ break; 167*eb8dc403SDave Cobbley } 168*eb8dc403SDave Cobbley- return 1; 169*eb8dc403SDave Cobbley } 170*eb8dc403SDave Cobbley 171*eb8dc403SDave Cobbley+ if (dynamic_strings == NULL) 172*eb8dc403SDave Cobbley+ return 1; 173*eb8dc403SDave Cobbley+ 174*eb8dc403SDave Cobbley+ /* Now read the DT_NEEDED and DT_SONAME entries. */ 175*eb8dc403SDave Cobbley+ for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL; 176*eb8dc403SDave Cobbley+ ++dyn_entry) 177*eb8dc403SDave Cobbley+ { 178*eb8dc403SDave Cobbley+ if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME) 179*eb8dc403SDave Cobbley+ { 180*eb8dc403SDave Cobbley+ char *name = dynamic_strings + dyn_entry->d_un.d_val; 181*eb8dc403SDave Cobbley+ check_ptr (name); 182*eb8dc403SDave Cobbley+ 183*eb8dc403SDave Cobbley+ if (dyn_entry->d_tag == DT_NEEDED) 184*eb8dc403SDave Cobbley+ { 185*eb8dc403SDave Cobbley+ 186*eb8dc403SDave Cobbley+ if (*flag == FLAG_ELF) 187*eb8dc403SDave Cobbley+ { 188*eb8dc403SDave Cobbley+ /* Check if this is enough to classify the binary. */ 189*eb8dc403SDave Cobbley+ for (j = 0; 190*eb8dc403SDave Cobbley+ j < sizeof (known_libs) / sizeof (known_libs [0]); 191*eb8dc403SDave Cobbley+ ++j) 192*eb8dc403SDave Cobbley+ if (strcmp (name, known_libs [j].soname) == 0) 193*eb8dc403SDave Cobbley+ { 194*eb8dc403SDave Cobbley+ *flag = known_libs [j].flag; 195*eb8dc403SDave Cobbley+ break; 196*eb8dc403SDave Cobbley+ } 197*eb8dc403SDave Cobbley+ } 198*eb8dc403SDave Cobbley+ } 199*eb8dc403SDave Cobbley+ 200*eb8dc403SDave Cobbley+ else if (dyn_entry->d_tag == DT_SONAME) 201*eb8dc403SDave Cobbley+ *soname = xstrdup (name); 202*eb8dc403SDave Cobbley+ 203*eb8dc403SDave Cobbley+ /* Do we have everything we need? */ 204*eb8dc403SDave Cobbley+ if (*soname && *flag != FLAG_ELF) 205*eb8dc403SDave Cobbley+ return 0; 206*eb8dc403SDave Cobbley+ } 207*eb8dc403SDave Cobbley+ } 208*eb8dc403SDave Cobbley+ 209*eb8dc403SDave Cobbley+ /* We reach this point only if the file doesn't contain a DT_SONAME 210*eb8dc403SDave Cobbley+ or if we can't classify the library. If it doesn't have a 211*eb8dc403SDave Cobbley+ soname, return the name of the library. */ 212*eb8dc403SDave Cobbley+ if (*soname == NULL) 213*eb8dc403SDave Cobbley+ *soname = xstrdup (lib); 214*eb8dc403SDave Cobbley+ 215*eb8dc403SDave Cobbley+ return 0; 216*eb8dc403SDave Cobbley+} 217*eb8dc403SDave Cobbley+ 218*eb8dc403SDave Cobbley+int 219*eb8dc403SDave Cobbley+process_elf_file64 (const char *file_name, const char *lib, int *flag, 220*eb8dc403SDave Cobbley+ unsigned int *osversion, char **soname, void *file_contents, 221*eb8dc403SDave Cobbley+ size_t file_length) 222*eb8dc403SDave Cobbley+{ 223*eb8dc403SDave Cobbley+ int i; 224*eb8dc403SDave Cobbley+ unsigned int j; 225*eb8dc403SDave Cobbley+ Elf64_Addr loadaddr; 226*eb8dc403SDave Cobbley+ unsigned int dynamic_addr; 227*eb8dc403SDave Cobbley+ size_t dynamic_size; 228*eb8dc403SDave Cobbley+ char *program_interpreter; 229*eb8dc403SDave Cobbley+ 230*eb8dc403SDave Cobbley+ Elf64_Ehdr *elf_header; 231*eb8dc403SDave Cobbley+ Elf64_Phdr *elf_pheader, *segment; 232*eb8dc403SDave Cobbley+ Elf64_Dyn *dynamic_segment, *dyn_entry; 233*eb8dc403SDave Cobbley+ char *dynamic_strings; 234*eb8dc403SDave Cobbley+ 235*eb8dc403SDave Cobbley+ elf_header = (Elf64_Ehdr *) file_contents; 236*eb8dc403SDave Cobbley+ *osversion = 0; 237*eb8dc403SDave Cobbley+ 238*eb8dc403SDave Cobbley if (elf_header->e_type != ET_DYN) 239*eb8dc403SDave Cobbley { 240*eb8dc403SDave Cobbley error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name, 241*eb8dc403SDave Cobbley@@ -81,7 +254,7 @@ process_elf_file (const char *file_name, 242*eb8dc403SDave Cobbley } 243*eb8dc403SDave Cobbley 244*eb8dc403SDave Cobbley /* Get information from elf program header. */ 245*eb8dc403SDave Cobbley- elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents); 246*eb8dc403SDave Cobbley+ elf_pheader = (Elf64_Phdr *) (elf_header->e_phoff + file_contents); 247*eb8dc403SDave Cobbley check_ptr (elf_pheader); 248*eb8dc403SDave Cobbley 249*eb8dc403SDave Cobbley /* The library is an elf library, now search for soname and 250*eb8dc403SDave Cobbley@@ -100,7 +273,7 @@ process_elf_file (const char *file_name, 251*eb8dc403SDave Cobbley switch (segment->p_type) 252*eb8dc403SDave Cobbley { 253*eb8dc403SDave Cobbley case PT_LOAD: 254*eb8dc403SDave Cobbley- if (loadaddr == (ElfW(Addr)) -1) 255*eb8dc403SDave Cobbley+ if (loadaddr == (Elf64_Addr) -1) 256*eb8dc403SDave Cobbley loadaddr = segment->p_vaddr - segment->p_offset; 257*eb8dc403SDave Cobbley break; 258*eb8dc403SDave Cobbley 259*eb8dc403SDave Cobbley@@ -129,16 +302,16 @@ process_elf_file (const char *file_name, 260*eb8dc403SDave Cobbley case PT_NOTE: 261*eb8dc403SDave Cobbley if (!*osversion && segment->p_filesz >= 32 && segment->p_align >= 4) 262*eb8dc403SDave Cobbley { 263*eb8dc403SDave Cobbley- ElfW(Word) *abi_note = (ElfW(Word) *) (file_contents 264*eb8dc403SDave Cobbley+ Elf64_Word *abi_note = (Elf64_Word *) (file_contents 265*eb8dc403SDave Cobbley + segment->p_offset); 266*eb8dc403SDave Cobbley- ElfW(Addr) size = segment->p_filesz; 267*eb8dc403SDave Cobbley+ Elf64_Addr size = segment->p_filesz; 268*eb8dc403SDave Cobbley 269*eb8dc403SDave Cobbley while (abi_note [0] != 4 || abi_note [1] != 16 270*eb8dc403SDave Cobbley || abi_note [2] != 1 271*eb8dc403SDave Cobbley || memcmp (abi_note + 3, "GNU", 4) != 0) 272*eb8dc403SDave Cobbley { 273*eb8dc403SDave Cobbley-#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word))) 274*eb8dc403SDave Cobbley- ElfW(Addr) note_size = 3 * sizeof (ElfW(Word)) 275*eb8dc403SDave Cobbley+#define ROUND(len) (((len) + sizeof (Elf64_Word) - 1) & -sizeof (Elf64_Word)) 276*eb8dc403SDave Cobbley+ Elf64_Addr note_size = 3 * sizeof (Elf64_Word) 277*eb8dc403SDave Cobbley + ROUND (abi_note[0]) 278*eb8dc403SDave Cobbley + ROUND (abi_note[1]); 279*eb8dc403SDave Cobbley 280*eb8dc403SDave Cobbley@@ -166,7 +339,7 @@ process_elf_file (const char *file_name, 281*eb8dc403SDave Cobbley } 282*eb8dc403SDave Cobbley 283*eb8dc403SDave Cobbley } 284*eb8dc403SDave Cobbley- if (loadaddr == (ElfW(Addr)) -1) 285*eb8dc403SDave Cobbley+ if (loadaddr == (Elf64_Addr) -1) 286*eb8dc403SDave Cobbley { 287*eb8dc403SDave Cobbley /* Very strange. */ 288*eb8dc403SDave Cobbley loadaddr = 0; 289*eb8dc403SDave Cobbley@@ -176,7 +349,7 @@ process_elf_file (const char *file_name, 290*eb8dc403SDave Cobbley if (dynamic_size == 0) 291*eb8dc403SDave Cobbley return 1; 292*eb8dc403SDave Cobbley 293*eb8dc403SDave Cobbley- dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr); 294*eb8dc403SDave Cobbley+ dynamic_segment = (Elf64_Dyn *) (file_contents + dynamic_addr); 295*eb8dc403SDave Cobbley check_ptr (dynamic_segment); 296*eb8dc403SDave Cobbley 297*eb8dc403SDave Cobbley /* Find the string table. */ 298*eb8dc403SDave Cobbley@@ -233,3 +406,33 @@ process_elf_file (const char *file_name, 299*eb8dc403SDave Cobbley 300*eb8dc403SDave Cobbley return 0; 301*eb8dc403SDave Cobbley } 302*eb8dc403SDave Cobbley+/* Returns 0 if everything is ok, != 0 in case of error. */ 303*eb8dc403SDave Cobbley+int 304*eb8dc403SDave Cobbley+process_elf_file (const char *file_name, const char *lib, int *flag, 305*eb8dc403SDave Cobbley+ unsigned int *osversion, char **soname, void *file_contents, 306*eb8dc403SDave Cobbley+ size_t file_length) 307*eb8dc403SDave Cobbley+{ 308*eb8dc403SDave Cobbley+ int i; 309*eb8dc403SDave Cobbley+ unsigned int j; 310*eb8dc403SDave Cobbley+ ElfW(Addr) loadaddr; 311*eb8dc403SDave Cobbley+ unsigned int dynamic_addr; 312*eb8dc403SDave Cobbley+ size_t dynamic_size; 313*eb8dc403SDave Cobbley+ char *program_interpreter; 314*eb8dc403SDave Cobbley+ 315*eb8dc403SDave Cobbley+ ElfW(Ehdr) *elf_header; 316*eb8dc403SDave Cobbley+ ElfW(Phdr) *elf_pheader, *segment; 317*eb8dc403SDave Cobbley+ ElfW(Dyn) *dynamic_segment, *dyn_entry; 318*eb8dc403SDave Cobbley+ char *dynamic_strings; 319*eb8dc403SDave Cobbley+ 320*eb8dc403SDave Cobbley+ elf_header = (ElfW(Ehdr) *) file_contents; 321*eb8dc403SDave Cobbley+ *osversion = 0; 322*eb8dc403SDave Cobbley+ 323*eb8dc403SDave Cobbley+ if (elf_header->e_ident [EI_CLASS] == ELFCLASS32) 324*eb8dc403SDave Cobbley+ return process_elf_file32(file_name, lib,flag, osversion, soname, file_contents, file_length); 325*eb8dc403SDave Cobbley+ else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64) 326*eb8dc403SDave Cobbley+ return process_elf_file64(file_name, lib,flag, osversion, soname, file_contents, file_length); 327*eb8dc403SDave Cobbley+ error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name); 328*eb8dc403SDave Cobbley+ return 1; 329*eb8dc403SDave Cobbley+} 330*eb8dc403SDave Cobbley+ 331*eb8dc403SDave Cobbley+ 332