func process_package(packages []string, filename string) { // RPM transcation stuff ts := C.rpmtsCreate() defer C.rpmtsFree(ts) C.rpmtsSetRootDir(ts, nil) C.rpmtsSetVSFlags(ts, C._RPMVSF_NOSIGNATURES) // create a lookup table for the files in debuginfo RPM // libarchive is too slow for doing this due to lzma decoding! cmode := C.CString("r") defer C.free(unsafe.Pointer(cmode)) debug_package := filename cfilename := C.CString(debug_package) defer C.free(unsafe.Pointer(cfilename)) /* debug_files := make(map[string]bool) dfd := C.Fopen(cfilename, cmode) defer C.Fclose(dfd) var dhdr C.Header drc := C.rpmReadPackageFile(ts, dfd, cfilename, &dhdr) if drc != C.RPMRC_OK { log.Println("[-] %s, broken RPM?", filename) return } defer C.headerFree(dhdr) fi := C.rpmfiNew(ts, dhdr, C.RPMTAG_BASENAMES, C.RPMFI_FLAGS_QUERY) defer C.rpmfiFree(fi) fi = C.rpmfiInit(fi, 0) for C.rpmfiNext(fi) >= 0 { fn := C.rpmfiFN(fi) // defer C.free(unsafe.Pointer(fn)) gfn := C.GoString(fn) if strings.HasSuffix(gfn, ".debug") { debug_files[gfn] = true } } */ // get the "dwz" content for this debug_package a := C.archive_read_new() defer C.archive_read_free(a) C.archive_read_support_filter_all(a) C.archive_read_support_format_all(a) r := C.archive_read_open_filename(a, cfilename, 30240) if r != C.ARCHIVE_OK { log.Println("[-] %s, broken archive?", debug_package) } pentry := C.archive_entry_new() var dwzfile *elf.File var err error for C.archive_read_next_header(a, &pentry) == C.ARCHIVE_OK { f := C.archive_entry_pathname(pentry) entryname := C.GoString(f) size := C.archive_entry_size(pentry) // skip folders mode := C.archive_entry_mode(pentry) gmode := int(mode) if gmode&0040000 != 0 { continue } // get the "dwz" content for this debug_package if strings.Contains(entryname, "lib/debug/.dwz/") { dwzbuf := unsafe.Pointer((*C.char)(C.malloc((C.size_t)(size)))) defer C.free(unsafe.Pointer(dwzbuf)) read_length := C.archive_read_data(a, dwzbuf, C.size_t(size)) log.Println("[DWZ] read", read_length, "bytes from", entryname) // C array to Go array without explicit copying // https://code.google.com/p/go-wiki/wiki/cgo // dwzdata := (*[1<<31 - 1]byte)(unsafe.Pointer(dwzbuf))[:size] // https://code.google.com/p/go-wiki/wiki/cgo#Turning_C_arrays_into_Go_slices length := int(size) hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(dwzbuf)), Len: length, Cap: length, } dwzdata := *(*[]byte)(unsafe.Pointer(&hdr)) if len(dwzdata) > 0 { dwzfile, err = elf.NewFile(bytes.NewReader(dwzdata)) if err != nil { log.Println(err) } } break } } // process ".debug" file(s) in debug_package m := make(map[string][]string) var debugfile *elf.File var e error b := C.archive_read_new() defer C.archive_read_free(b) C.archive_read_support_filter_all(b) C.archive_read_support_format_all(b) pentry = C.archive_entry_new() C.archive_read_open_filename(b, cfilename, 30240) for C.archive_read_next_header(b, &pentry) == C.ARCHIVE_OK { f := C.archive_entry_pathname(pentry) entryname := C.GoString(f) size := C.archive_entry_size(pentry) // skip folders and symlinks mode := C.archive_entry_mode(pentry) gmode := int(mode) // S_IFLNK 0120000 symbolic link // S_IFMT 0170000 bit mask for the file type bit fields // S_IFDIR 0040000 directory if gmode&0040000 != 0 || gmode&0170000 == 0120000 { continue } // skip zero sized entries if size == 0 { continue } // skip non-debug files if !strings.HasSuffix(entryname, ".debug") || strings.Contains(entryname, "debug/.build-id/") { continue } // log.Println("<+> loading", entryname) // allocate buffer for reading data cbuf := unsafe.Pointer((*C.char)(C.malloc((C.size_t)(size)))) read_length := C.archive_read_data(b, cbuf, C.size_t(size)) log.Println("[DEBUG] read", read_length, "bytes from", entryname) // data := (*[1<<31 - 1]byte)(unsafe.Pointer(cbuf))[:size] // will break at 2.14 GB! // https://code.google.com/p/go-wiki/wiki/cgo#Turning_C_arrays_into_Go_slices length := int(size) hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(cbuf)), Len: length, Cap: length, } data := *(*[]byte)(unsafe.Pointer(&hdr)) if len(data) > 0 { debugfile, e = elf.NewFile(bytes.NewReader(data)) if e != nil { log.Println(e, entryname, len(data)) continue } } else { log.Println(len(data), entryname, debug_package) } // log.Println("<+> loaded", entryname) // time.Sleep(1 * time.Millisecond) // real action time ;( output := producer(debugfile, dwzfile, entryname, filename) m[entryname] = output C.free(unsafe.Pointer(cbuf)) } stuff, bad := json.Marshal(m) if bad != nil { log.Panic(bad) } fmt.Println(string(stuff)) }
func process_packages(packages []string, debug_packages []string) { m := make(map[string][]string) ts := C.rpmtsCreate() defer C.rpmtsFree(ts) C.rpmtsSetRootDir(ts, nil) C.rpmtsSetVSFlags(ts, C._RPMVSF_NOSIGNATURES) for _, filename := range packages { cfilename := C.CString(filename) defer C.free(unsafe.Pointer(cfilename)) cmode := C.CString("r") defer C.free(unsafe.Pointer(cmode)) // extract metadata (RPM headers) from filename fd := C.Fopen(cfilename, cmode) if fd == nil { log.Println("fd == NULL while processing", filename) time.Sleep(100000 * time.Millisecond) panic("^^^") } var hdr C.Header rc := C.rpmReadPackageFile(ts, fd, cfilename, &hdr) // read header stuff if rc != C.RPMRC_OK { log.Println("[-] broken RPM?", filename) continue } // extract various "tags" from the RPM file csrpm := C.headerGetAsString(hdr, C.RPMTAG_SOURCERPM) defer C.free((unsafe.Pointer)(csrpm)) srpm := C.GoString(csrpm) C.headerFree(hdr) /* cnvr := C.headerGetAsString(hdr, C.RPMTAG_NVRA) defer C.free((unsafe.Pointer)(cnvr)) nvr := C.GoString(cnvr) log.Println(nvr) */ // determine the name of debuginfo package from srpm name re := regexp.MustCompile("(?P<name>.*)-.*-.*") res := re.FindAllStringSubmatch(srpm, -1)[0] if len(res) == 0 { log.Println("[-] SRPM name missing for", filename) } names := re.SubexpNames() md := map[string]string{} for i, n := range res { md[names[i]] = n } target_debug_package := md["name"] + "-debuginfo-" // do we have this "target_debug_package" in "debug_packages"? debug_package := "" re = regexp.MustCompile(regexp.QuoteMeta(target_debug_package)) for _, name := range debug_packages { if re.MatchString(path.Base(name)+"\\d") == true { debug_package = name } } if debug_package == "" { log.Println("[-] debuginfo missing (during preliminary scan) for", filename) } m[debug_package] = append(m[debug_package], filename) C.Fclose(fd) // critical step! } b, err := json.Marshal(m) if err != nil { log.Panic("JSON encoding problem ;(") } fmt.Println(string(b)) // output }